diff --git a/crates/std/Cargo.toml b/crates/std/Cargo.toml index 9d12f40..6baaff8 100644 --- a/crates/std/Cargo.toml +++ b/crates/std/Cargo.toml @@ -4,6 +4,7 @@ version = "0.1.0" edition = "2024" [dependencies] +hashbrown = "0.16" os-std-macros = { path = "../os-std-macros" } shared = { path = "../shared", features = ["user"] } io = { path = "../io", features = ["alloc"] } diff --git a/crates/std/src/collections/hash/map.rs b/crates/std/src/collections/hash/map.rs new file mode 100644 index 0000000..b82beb3 --- /dev/null +++ b/crates/std/src/collections/hash/map.rs @@ -0,0 +1,3034 @@ +#[cfg(test)] +mod tests; + +use hashbrown::hash_map as base; + +use self::Entry::*; +use crate::alloc::{Allocator, Global}; +use crate::borrow::Borrow; +use crate::collections::{TryReserveError, TryReserveErrorKind}; +use crate::error::Error; +use crate::fmt::{self, Debug}; +use crate::hash::{BuildHasher, Hash, RandomState}; +use crate::iter::FusedIterator; +use crate::ops::Index; + +/// A [hash map] implemented with quadratic probing and SIMD lookup. +/// +/// By default, `HashMap` uses a hashing algorithm selected to provide +/// resistance against HashDoS attacks. The algorithm is randomly seeded, and a +/// reasonable best-effort is made to generate this seed from a high quality, +/// secure source of randomness provided by the host without blocking the +/// program. Because of this, the randomness of the seed depends on the output +/// quality of the system's random number coroutine when the seed is created. +/// In particular, seeds generated when the system's entropy pool is abnormally +/// low such as during system boot may be of a lower quality. +/// +/// The default hashing algorithm is currently SipHash 1-3, though this is +/// subject to change at any point in the future. While its performance is very +/// competitive for medium sized keys, other hashing algorithms will outperform +/// it for small keys such as integers as well as large keys such as long +/// strings, though those algorithms will typically *not* protect against +/// attacks such as HashDoS. +/// +/// The hashing algorithm can be replaced on a per-`HashMap` basis using the +/// [`default`], [`with_hasher`], and [`with_capacity_and_hasher`] methods. +/// There are many alternative [hashing algorithms available on crates.io]. +/// +/// It is required that the keys implement the [`Eq`] and [`Hash`] traits, although +/// this can frequently be achieved by using `#[derive(PartialEq, Eq, Hash)]`. +/// If you implement these yourself, it is important that the following +/// property holds: +/// +/// ```text +/// k1 == k2 -> hash(k1) == hash(k2) +/// ``` +/// +/// In other words, if two keys are equal, their hashes must be equal. +/// Violating this property is a logic error. +/// +/// It is also a logic error for a key to be modified in such a way that the key's +/// hash, as determined by the [`Hash`] trait, or its equality, as determined by +/// the [`Eq`] trait, changes while it is in the map. This is normally only +/// possible through [`Cell`], [`RefCell`], global state, I/O, or unsafe code. +/// +/// The behavior resulting from either logic error is not specified, but will +/// be encapsulated to the `HashMap` that observed the logic error and not +/// result in undefined behavior. This could include panics, incorrect results, +/// aborts, memory leaks, and non-termination. +/// +/// The hash table implementation is a Rust port of Google's [SwissTable]. +/// The original C++ version of SwissTable can be found [here], and this +/// [CppCon talk] gives an overview of how the algorithm works. +/// +/// [hash map]: crate::collections#use-a-hashmap-when +/// [hashing algorithms available on crates.io]: https://crates.io/keywords/hasher +/// [SwissTable]: https://abseil.io/blog/20180927-swisstables +/// [here]: https://github.com/abseil/abseil-cpp/blob/master/absl/container/internal/raw_hash_set.h +/// [CppCon talk]: https://www.youtube.com/watch?v=ncHmEUmJZf4 +/// +/// # Examples +/// +/// ``` +/// use std::collections::HashMap; +/// +/// // Type inference lets us omit an explicit type signature (which +/// // would be `HashMap` in this example). +/// let mut book_reviews = HashMap::new(); +/// +/// // Review some books. +/// book_reviews.insert( +/// "Adventures of Huckleberry Finn".to_string(), +/// "My favorite book.".to_string(), +/// ); +/// book_reviews.insert( +/// "Grimms' Fairy Tales".to_string(), +/// "Masterpiece.".to_string(), +/// ); +/// book_reviews.insert( +/// "Pride and Prejudice".to_string(), +/// "Very enjoyable.".to_string(), +/// ); +/// book_reviews.insert( +/// "The Adventures of Sherlock Holmes".to_string(), +/// "Eye lyked it alot.".to_string(), +/// ); +/// +/// // Check for a specific one. +/// // When collections store owned values (String), they can still be +/// // queried using references (&str). +/// if !book_reviews.contains_key("Les Misérables") { +/// println!("We've got {} reviews, but Les Misérables ain't one.", +/// book_reviews.len()); +/// } +/// +/// // oops, this review has a lot of spelling mistakes, let's delete it. +/// book_reviews.remove("The Adventures of Sherlock Holmes"); +/// +/// // Look up the values associated with some keys. +/// let to_find = ["Pride and Prejudice", "Alice's Adventure in Wonderland"]; +/// for &book in &to_find { +/// match book_reviews.get(book) { +/// Some(review) => println!("{book}: {review}"), +/// None => println!("{book} is unreviewed.") +/// } +/// } +/// +/// // Look up the value for a key (will panic if the key is not found). +/// println!("Review for Jane: {}", book_reviews["Pride and Prejudice"]); +/// +/// // Iterate over everything. +/// for (book, review) in &book_reviews { +/// println!("{book}: \"{review}\""); +/// } +/// ``` +/// +/// A `HashMap` with a known list of items can be initialized from an array: +/// +/// ``` +/// use std::collections::HashMap; +/// +/// let solar_distance = HashMap::from([ +/// ("Mercury", 0.4), +/// ("Venus", 0.7), +/// ("Earth", 1.0), +/// ("Mars", 1.5), +/// ]); +/// ``` +/// +/// ## `Entry` API +/// +/// `HashMap` implements an [`Entry` API](#method.entry), which allows +/// for complex methods of getting, setting, updating and removing keys and +/// their values: +/// +/// ``` +/// use std::collections::HashMap; +/// +/// // type inference lets us omit an explicit type signature (which +/// // would be `HashMap<&str, u8>` in this example). +/// let mut player_stats = HashMap::new(); +/// +/// fn random_stat_buff() -> u8 { +/// // could actually return some random value here - let's just return +/// // some fixed value for now +/// 42 +/// } +/// +/// // insert a key only if it doesn't already exist +/// player_stats.entry("health").or_insert(100); +/// +/// // insert a key using a function that provides a new value only if it +/// // doesn't already exist +/// player_stats.entry("defence").or_insert_with(random_stat_buff); +/// +/// // update a key, guarding against the key possibly not being set +/// let stat = player_stats.entry("attack").or_insert(100); +/// *stat += random_stat_buff(); +/// +/// // modify an entry before an insert with in-place mutation +/// player_stats.entry("mana").and_modify(|mana| *mana += 200).or_insert(100); +/// ``` +/// +/// ## Usage with custom key types +/// +/// The easiest way to use `HashMap` with a custom key type is to derive [`Eq`] and [`Hash`]. +/// We must also derive [`PartialEq`]. +/// +/// [`RefCell`]: crate::cell::RefCell +/// [`Cell`]: crate::cell::Cell +/// [`default`]: Default::default +/// [`with_hasher`]: Self::with_hasher +/// [`with_capacity_and_hasher`]: Self::with_capacity_and_hasher +/// +/// ``` +/// use std::collections::HashMap; +/// +/// #[derive(Hash, Eq, PartialEq, Debug)] +/// struct Viking { +/// name: String, +/// country: String, +/// } +/// +/// impl Viking { +/// /// Creates a new Viking. +/// fn new(name: &str, country: &str) -> Viking { +/// Viking { name: name.to_string(), country: country.to_string() } +/// } +/// } +/// +/// // Use a HashMap to store the vikings' health points. +/// let vikings = HashMap::from([ +/// (Viking::new("Einar", "Norway"), 25), +/// (Viking::new("Olaf", "Denmark"), 24), +/// (Viking::new("Harald", "Iceland"), 12), +/// ]); +/// +/// // Use derived implementation to print the status of the vikings. +/// for (viking, health) in &vikings { +/// println!("{viking:?} has {health} hp"); +/// } +/// ``` +/// +/// # Usage in `const` and `static` +/// +/// As explained above, `HashMap` is randomly seeded: each `HashMap` instance uses a different seed, +/// which means that `HashMap::new` normally cannot be used in a `const` or `static` initializer. +/// +/// However, if you need to use a `HashMap` in a `const` or `static` initializer while retaining +/// random seed generation, you can wrap the `HashMap` in [`LazyLock`]. +/// +/// Alternatively, you can construct a `HashMap` in a `const` or `static` initializer using a different +/// hasher that does not rely on a random seed. **Be aware that a `HashMap` created this way is not +/// resistant to HashDoS attacks!** +/// +/// [`LazyLock`]: crate::sync::LazyLock +/// ```rust +/// use std::collections::HashMap; +/// use std::hash::{BuildHasherDefault, DefaultHasher}; +/// use std::sync::{LazyLock, Mutex}; +/// +/// // HashMaps with a fixed, non-random hasher +/// const NONRANDOM_EMPTY_MAP: HashMap, BuildHasherDefault> = +/// HashMap::with_hasher(BuildHasherDefault::new()); +/// static NONRANDOM_MAP: Mutex, BuildHasherDefault>> = +/// Mutex::new(HashMap::with_hasher(BuildHasherDefault::new())); +/// +/// // HashMaps using LazyLock to retain random seeding +/// const RANDOM_EMPTY_MAP: LazyLock>> = +/// LazyLock::new(HashMap::new); +/// static RANDOM_MAP: LazyLock>>> = +/// LazyLock::new(|| Mutex::new(HashMap::new())); +/// ``` + +#[cfg_attr(not(test), rustc_diagnostic_item = "HashMap")] +#[stable(feature = "rust1", since = "1.0.0")] +#[rustc_insignificant_dtor] +pub struct HashMap< + K, + V, + S = RandomState, + #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, +> { + base: base::HashMap, +} + +impl HashMap { + /// Creates an empty `HashMap`. + /// + /// The hash map is initially created with a capacity of 0, so it will not allocate until it + /// is first inserted into. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashMap; + /// let mut map: HashMap<&str, i32> = HashMap::new(); + /// ``` + #[inline] + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + pub fn new() -> HashMap { + Default::default() + } + + /// Creates an empty `HashMap` with at least the specified capacity. + /// + /// The hash map will be able to hold at least `capacity` elements without + /// reallocating. This method is allowed to allocate for more elements than + /// `capacity`. If `capacity` is zero, the hash map will not allocate. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashMap; + /// let mut map: HashMap<&str, i32> = HashMap::with_capacity(10); + /// ``` + #[inline] + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + pub fn with_capacity(capacity: usize) -> HashMap { + HashMap::with_capacity_and_hasher(capacity, Default::default()) + } +} + +impl HashMap { + /// Creates an empty `HashMap` using the given allocator. + /// + /// The hash map is initially created with a capacity of 0, so it will not allocate until it + /// is first inserted into. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashMap; + /// let mut map: HashMap<&str, i32> = HashMap::new(); + /// ``` + #[inline] + #[must_use] + #[unstable(feature = "allocator_api", issue = "32838")] + pub fn new_in(alloc: A) -> Self { + HashMap::with_hasher_in(Default::default(), alloc) + } + + /// Creates an empty `HashMap` with at least the specified capacity using + /// the given allocator. + /// + /// The hash map will be able to hold at least `capacity` elements without + /// reallocating. This method is allowed to allocate for more elements than + /// `capacity`. If `capacity` is zero, the hash map will not allocate. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashMap; + /// let mut map: HashMap<&str, i32> = HashMap::with_capacity(10); + /// ``` + #[inline] + #[must_use] + #[unstable(feature = "allocator_api", issue = "32838")] + pub fn with_capacity_in(capacity: usize, alloc: A) -> Self { + HashMap::with_capacity_and_hasher_in(capacity, Default::default(), alloc) + } +} + +impl HashMap { + /// Creates an empty `HashMap` which will use the given hash builder to hash + /// keys. + /// + /// The created map has the default initial capacity. + /// + /// Warning: `hash_builder` is normally randomly generated, and + /// is designed to allow HashMaps to be resistant to attacks that + /// cause many collisions and very poor performance. Setting it + /// manually using this function can expose a DoS attack vector. + /// + /// The `hash_builder` passed should implement the [`BuildHasher`] trait for + /// the `HashMap` to be useful, see its documentation for details. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashMap; + /// use std::hash::RandomState; + /// + /// let s = RandomState::new(); + /// let mut map = HashMap::with_hasher(s); + /// map.insert(1, 2); + /// ``` + #[inline] + #[stable(feature = "hashmap_build_hasher", since = "1.7.0")] + #[rustc_const_stable(feature = "const_collections_with_hasher", since = "1.85.0")] + pub const fn with_hasher(hash_builder: S) -> HashMap { + HashMap { base: base::HashMap::with_hasher(hash_builder) } + } + + /// Creates an empty `HashMap` with at least the specified capacity, using + /// `hasher` to hash the keys. + /// + /// The hash map will be able to hold at least `capacity` elements without + /// reallocating. This method is allowed to allocate for more elements than + /// `capacity`. If `capacity` is zero, the hash map will not allocate. + /// + /// Warning: `hasher` is normally randomly generated, and + /// is designed to allow HashMaps to be resistant to attacks that + /// cause many collisions and very poor performance. Setting it + /// manually using this function can expose a DoS attack vector. + /// + /// The `hasher` passed should implement the [`BuildHasher`] trait for + /// the `HashMap` to be useful, see its documentation for details. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashMap; + /// use std::hash::RandomState; + /// + /// let s = RandomState::new(); + /// let mut map = HashMap::with_capacity_and_hasher(10, s); + /// map.insert(1, 2); + /// ``` + #[inline] + #[stable(feature = "hashmap_build_hasher", since = "1.7.0")] + pub fn with_capacity_and_hasher(capacity: usize, hasher: S) -> HashMap { + HashMap { base: base::HashMap::with_capacity_and_hasher(capacity, hasher) } + } +} + +impl HashMap { + /// Creates an empty `HashMap` which will use the given hash builder and + /// allocator. + /// + /// The created map has the default initial capacity. + /// + /// Warning: `hash_builder` is normally randomly generated, and + /// is designed to allow HashMaps to be resistant to attacks that + /// cause many collisions and very poor performance. Setting it + /// manually using this function can expose a DoS attack vector. + /// + /// The `hash_builder` passed should implement the [`BuildHasher`] trait for + /// the `HashMap` to be useful, see its documentation for details. + #[inline] + #[unstable(feature = "allocator_api", issue = "32838")] + pub fn with_hasher_in(hash_builder: S, alloc: A) -> Self { + HashMap { base: base::HashMap::with_hasher_in(hash_builder, alloc) } + } + + /// Creates an empty `HashMap` with at least the specified capacity, using + /// `hasher` to hash the keys and `alloc` to allocate memory. + /// + /// The hash map will be able to hold at least `capacity` elements without + /// reallocating. This method is allowed to allocate for more elements than + /// `capacity`. If `capacity` is zero, the hash map will not allocate. + /// + /// Warning: `hasher` is normally randomly generated, and + /// is designed to allow HashMaps to be resistant to attacks that + /// cause many collisions and very poor performance. Setting it + /// manually using this function can expose a DoS attack vector. + /// + /// The `hasher` passed should implement the [`BuildHasher`] trait for + /// the `HashMap` to be useful, see its documentation for details. + /// + #[inline] + #[unstable(feature = "allocator_api", issue = "32838")] + pub fn with_capacity_and_hasher_in(capacity: usize, hash_builder: S, alloc: A) -> Self { + HashMap { base: base::HashMap::with_capacity_and_hasher_in(capacity, hash_builder, alloc) } + } + + /// Returns the number of elements the map can hold without reallocating. + /// + /// This number is a lower bound; the `HashMap` might be able to hold + /// more, but is guaranteed to be able to hold at least this many. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashMap; + /// let map: HashMap = HashMap::with_capacity(100); + /// assert!(map.capacity() >= 100); + /// ``` + #[inline] + #[stable(feature = "rust1", since = "1.0.0")] + pub fn capacity(&self) -> usize { + self.base.capacity() + } + + /// An iterator visiting all keys in arbitrary order. + /// The iterator element type is `&'a K`. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashMap; + /// + /// let map = HashMap::from([ + /// ("a", 1), + /// ("b", 2), + /// ("c", 3), + /// ]); + /// + /// for key in map.keys() { + /// println!("{key}"); + /// } + /// ``` + /// + /// # Performance + /// + /// In the current implementation, iterating over keys takes O(capacity) time + /// instead of O(len) because it internally visits empty buckets too. + #[rustc_lint_query_instability] + #[stable(feature = "rust1", since = "1.0.0")] + pub fn keys(&self) -> Keys<'_, K, V> { + Keys { inner: self.iter() } + } + + /// Creates a consuming iterator visiting all the keys in arbitrary order. + /// The map cannot be used after calling this. + /// The iterator element type is `K`. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashMap; + /// + /// let map = HashMap::from([ + /// ("a", 1), + /// ("b", 2), + /// ("c", 3), + /// ]); + /// + /// let mut vec: Vec<&str> = map.into_keys().collect(); + /// // The `IntoKeys` iterator produces keys in arbitrary order, so the + /// // keys must be sorted to test them against a sorted array. + /// vec.sort_unstable(); + /// assert_eq!(vec, ["a", "b", "c"]); + /// ``` + /// + /// # Performance + /// + /// In the current implementation, iterating over keys takes O(capacity) time + /// instead of O(len) because it internally visits empty buckets too. + #[inline] + #[rustc_lint_query_instability] + #[stable(feature = "map_into_keys_values", since = "1.54.0")] + pub fn into_keys(self) -> IntoKeys { + IntoKeys { inner: self.into_iter() } + } + + /// An iterator visiting all values in arbitrary order. + /// The iterator element type is `&'a V`. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashMap; + /// + /// let map = HashMap::from([ + /// ("a", 1), + /// ("b", 2), + /// ("c", 3), + /// ]); + /// + /// for val in map.values() { + /// println!("{val}"); + /// } + /// ``` + /// + /// # Performance + /// + /// In the current implementation, iterating over values takes O(capacity) time + /// instead of O(len) because it internally visits empty buckets too. + #[rustc_lint_query_instability] + #[stable(feature = "rust1", since = "1.0.0")] + pub fn values(&self) -> Values<'_, K, V> { + Values { inner: self.iter() } + } + + /// An iterator visiting all values mutably in arbitrary order. + /// The iterator element type is `&'a mut V`. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashMap; + /// + /// let mut map = HashMap::from([ + /// ("a", 1), + /// ("b", 2), + /// ("c", 3), + /// ]); + /// + /// for val in map.values_mut() { + /// *val = *val + 10; + /// } + /// + /// for val in map.values() { + /// println!("{val}"); + /// } + /// ``` + /// + /// # Performance + /// + /// In the current implementation, iterating over values takes O(capacity) time + /// instead of O(len) because it internally visits empty buckets too. + #[rustc_lint_query_instability] + #[stable(feature = "map_values_mut", since = "1.10.0")] + pub fn values_mut(&mut self) -> ValuesMut<'_, K, V> { + ValuesMut { inner: self.iter_mut() } + } + + /// Creates a consuming iterator visiting all the values in arbitrary order. + /// The map cannot be used after calling this. + /// The iterator element type is `V`. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashMap; + /// + /// let map = HashMap::from([ + /// ("a", 1), + /// ("b", 2), + /// ("c", 3), + /// ]); + /// + /// let mut vec: Vec = map.into_values().collect(); + /// // The `IntoValues` iterator produces values in arbitrary order, so + /// // the values must be sorted to test them against a sorted array. + /// vec.sort_unstable(); + /// assert_eq!(vec, [1, 2, 3]); + /// ``` + /// + /// # Performance + /// + /// In the current implementation, iterating over values takes O(capacity) time + /// instead of O(len) because it internally visits empty buckets too. + #[inline] + #[rustc_lint_query_instability] + #[stable(feature = "map_into_keys_values", since = "1.54.0")] + pub fn into_values(self) -> IntoValues { + IntoValues { inner: self.into_iter() } + } + + /// An iterator visiting all key-value pairs in arbitrary order. + /// The iterator element type is `(&'a K, &'a V)`. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashMap; + /// + /// let map = HashMap::from([ + /// ("a", 1), + /// ("b", 2), + /// ("c", 3), + /// ]); + /// + /// for (key, val) in map.iter() { + /// println!("key: {key} val: {val}"); + /// } + /// ``` + /// + /// # Performance + /// + /// In the current implementation, iterating over map takes O(capacity) time + /// instead of O(len) because it internally visits empty buckets too. + #[rustc_lint_query_instability] + #[stable(feature = "rust1", since = "1.0.0")] + pub fn iter(&self) -> Iter<'_, K, V> { + Iter { base: self.base.iter() } + } + + /// An iterator visiting all key-value pairs in arbitrary order, + /// with mutable references to the values. + /// The iterator element type is `(&'a K, &'a mut V)`. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashMap; + /// + /// let mut map = HashMap::from([ + /// ("a", 1), + /// ("b", 2), + /// ("c", 3), + /// ]); + /// + /// // Update all values + /// for (_, val) in map.iter_mut() { + /// *val *= 2; + /// } + /// + /// for (key, val) in &map { + /// println!("key: {key} val: {val}"); + /// } + /// ``` + /// + /// # Performance + /// + /// In the current implementation, iterating over map takes O(capacity) time + /// instead of O(len) because it internally visits empty buckets too. + #[rustc_lint_query_instability] + #[stable(feature = "rust1", since = "1.0.0")] + pub fn iter_mut(&mut self) -> IterMut<'_, K, V> { + IterMut { base: self.base.iter_mut() } + } + + /// Returns the number of elements in the map. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashMap; + /// + /// let mut a = HashMap::new(); + /// assert_eq!(a.len(), 0); + /// a.insert(1, "a"); + /// assert_eq!(a.len(), 1); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn len(&self) -> usize { + self.base.len() + } + + /// Returns `true` if the map contains no elements. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashMap; + /// + /// let mut a = HashMap::new(); + /// assert!(a.is_empty()); + /// a.insert(1, "a"); + /// assert!(!a.is_empty()); + /// ``` + #[inline] + #[stable(feature = "rust1", since = "1.0.0")] + pub fn is_empty(&self) -> bool { + self.base.is_empty() + } + + /// Clears the map, returning all key-value pairs as an iterator. Keeps the + /// allocated memory for reuse. + /// + /// If the returned iterator is dropped before being fully consumed, it + /// drops the remaining key-value pairs. The returned iterator keeps a + /// mutable borrow on the map to optimize its implementation. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashMap; + /// + /// let mut a = HashMap::new(); + /// a.insert(1, "a"); + /// a.insert(2, "b"); + /// + /// for (k, v) in a.drain().take(1) { + /// assert!(k == 1 || k == 2); + /// assert!(v == "a" || v == "b"); + /// } + /// + /// assert!(a.is_empty()); + /// ``` + #[inline] + #[rustc_lint_query_instability] + #[stable(feature = "drain", since = "1.6.0")] + pub fn drain(&mut self) -> Drain<'_, K, V, A> { + Drain { base: self.base.drain() } + } + + /// Creates an iterator which uses a closure to determine if an element (key-value pair) should be removed. + /// + /// If the closure returns `true`, the element is removed from the map and + /// yielded. If the closure returns `false`, or panics, the element remains + /// in the map and will not be yielded. + /// + /// The iterator also lets you mutate the value of each element in the + /// closure, regardless of whether you choose to keep or remove it. + /// + /// 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. + /// + /// [`retain`]: HashMap::retain + /// + /// # Examples + /// + /// Splitting a map into even and odd keys, reusing the original map: + /// + /// ``` + /// use std::collections::HashMap; + /// + /// let mut map: HashMap = (0..8).map(|x| (x, x)).collect(); + /// let extracted: HashMap = map.extract_if(|k, _v| k % 2 == 0).collect(); + /// + /// let mut evens = extracted.keys().copied().collect::>(); + /// let mut odds = map.keys().copied().collect::>(); + /// evens.sort(); + /// odds.sort(); + /// + /// assert_eq!(evens, vec![0, 2, 4, 6]); + /// assert_eq!(odds, vec![1, 3, 5, 7]); + /// ``` + #[inline] + #[rustc_lint_query_instability] + #[stable(feature = "hash_extract_if", since = "1.88.0")] + pub fn extract_if(&mut self, pred: F) -> ExtractIf<'_, K, V, F, A> + where + F: FnMut(&K, &mut V) -> bool, + { + ExtractIf { base: self.base.extract_if(pred) } + } + + /// Retains only the elements specified by the predicate. + /// + /// In other words, remove all pairs `(k, v)` for which `f(&k, &mut v)` returns `false`. + /// The elements are visited in unsorted (and unspecified) order. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashMap; + /// + /// let mut map: HashMap = (0..8).map(|x| (x, x*10)).collect(); + /// map.retain(|&k, _| k % 2 == 0); + /// assert_eq!(map.len(), 4); + /// ``` + /// + /// # Performance + /// + /// In the current implementation, this operation takes O(capacity) time + /// instead of O(len) because it internally visits empty buckets too. + #[inline] + #[rustc_lint_query_instability] + #[stable(feature = "retain_hash_collection", since = "1.18.0")] + pub fn retain(&mut self, f: F) + where + F: FnMut(&K, &mut V) -> bool, + { + self.base.retain(f) + } + + /// Clears the map, removing all key-value pairs. Keeps the allocated memory + /// for reuse. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashMap; + /// + /// let mut a = HashMap::new(); + /// a.insert(1, "a"); + /// a.clear(); + /// assert!(a.is_empty()); + /// ``` + #[inline] + #[stable(feature = "rust1", since = "1.0.0")] + pub fn clear(&mut self) { + self.base.clear(); + } + + /// Returns a reference to the map's [`BuildHasher`]. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashMap; + /// use std::hash::RandomState; + /// + /// let hasher = RandomState::new(); + /// let map: HashMap = HashMap::with_hasher(hasher); + /// let hasher: &RandomState = map.hasher(); + /// ``` + #[inline] + #[stable(feature = "hashmap_public_hasher", since = "1.9.0")] + pub fn hasher(&self) -> &S { + self.base.hasher() + } +} + +impl HashMap +where + K: Eq + Hash, + S: BuildHasher, + A: Allocator, +{ + /// Reserves capacity for at least `additional` more elements to be inserted + /// in the `HashMap`. The collection may reserve more space to speculatively + /// avoid frequent reallocations. After calling `reserve`, + /// capacity will be greater than or equal to `self.len() + additional`. + /// Does nothing if capacity is already sufficient. + /// + /// # Panics + /// + /// Panics if the new allocation size overflows [`usize`]. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashMap; + /// let mut map: HashMap<&str, i32> = HashMap::new(); + /// map.reserve(10); + /// ``` + #[inline] + #[stable(feature = "rust1", since = "1.0.0")] + pub fn reserve(&mut self, additional: usize) { + self.base.reserve(additional) + } + + /// Tries to reserve capacity for at least `additional` more elements to be inserted + /// in the `HashMap`. The collection may reserve more space to speculatively + /// avoid frequent reallocations. After calling `try_reserve`, + /// capacity will be greater than or equal to `self.len() + additional` if + /// it returns `Ok(())`. + /// Does nothing if capacity is already sufficient. + /// + /// # Errors + /// + /// If the capacity overflows, or the allocator reports a failure, then an error + /// is returned. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashMap; + /// + /// let mut map: HashMap<&str, isize> = HashMap::new(); + /// map.try_reserve(10).expect("why is the test harness OOMing on a handful of bytes?"); + /// ``` + #[inline] + #[stable(feature = "try_reserve", since = "1.57.0")] + pub fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError> { + self.base.try_reserve(additional).map_err(map_try_reserve_error) + } + + /// Shrinks the capacity of the map as much as possible. It will drop + /// down as much as possible while maintaining the internal rules + /// and possibly leaving some space in accordance with the resize policy. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashMap; + /// + /// let mut map: HashMap = HashMap::with_capacity(100); + /// map.insert(1, 2); + /// map.insert(3, 4); + /// assert!(map.capacity() >= 100); + /// map.shrink_to_fit(); + /// assert!(map.capacity() >= 2); + /// ``` + #[inline] + #[stable(feature = "rust1", since = "1.0.0")] + pub fn shrink_to_fit(&mut self) { + self.base.shrink_to_fit(); + } + + /// Shrinks the capacity of the map with a lower limit. It will drop + /// down no lower than the supplied limit while maintaining the internal rules + /// and possibly leaving some space in accordance with the resize policy. + /// + /// If the current capacity is less than the lower limit, this is a no-op. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashMap; + /// + /// let mut map: HashMap = HashMap::with_capacity(100); + /// map.insert(1, 2); + /// map.insert(3, 4); + /// assert!(map.capacity() >= 100); + /// map.shrink_to(10); + /// assert!(map.capacity() >= 10); + /// map.shrink_to(0); + /// assert!(map.capacity() >= 2); + /// ``` + #[inline] + #[stable(feature = "shrink_to", since = "1.56.0")] + pub fn shrink_to(&mut self, min_capacity: usize) { + self.base.shrink_to(min_capacity); + } + + /// Gets the given key's corresponding entry in the map for in-place manipulation. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashMap; + /// + /// let mut letters = HashMap::new(); + /// + /// for ch in "a short treatise on fungi".chars() { + /// letters.entry(ch).and_modify(|counter| *counter += 1).or_insert(1); + /// } + /// + /// assert_eq!(letters[&'s'], 2); + /// assert_eq!(letters[&'t'], 3); + /// assert_eq!(letters[&'u'], 1); + /// assert_eq!(letters.get(&'y'), None); + /// ``` + #[inline] + #[stable(feature = "rust1", since = "1.0.0")] + pub fn entry(&mut self, key: K) -> Entry<'_, K, V, A> { + map_entry(self.base.rustc_entry(key)) + } + + /// Returns a reference to the value corresponding to the key. + /// + /// The key may be any borrowed form of the map's key type, but + /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for + /// the key type. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashMap; + /// + /// let mut map = HashMap::new(); + /// map.insert(1, "a"); + /// assert_eq!(map.get(&1), Some(&"a")); + /// assert_eq!(map.get(&2), None); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn get(&self, k: &Q) -> Option<&V> + where + K: Borrow, + Q: Hash + Eq, + { + self.base.get(k) + } + + /// Returns the key-value pair corresponding to the supplied key. This is + /// potentially useful: + /// - for key types where non-identical keys can be considered equal; + /// - for getting the `&K` stored key value from a borrowed `&Q` lookup key; or + /// - for getting a reference to a key with the same lifetime as the collection. + /// + /// The supplied key may be any borrowed form of the map's key type, but + /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for + /// the key type. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashMap; + /// use std::hash::{Hash, Hasher}; + /// + /// #[derive(Clone, Copy, Debug)] + /// struct S { + /// id: u32, + /// # #[allow(unused)] // prevents a "field `name` is never read" error + /// name: &'static str, // ignored by equality and hashing operations + /// } + /// + /// impl PartialEq for S { + /// fn eq(&self, other: &S) -> bool { + /// self.id == other.id + /// } + /// } + /// + /// impl Eq for S {} + /// + /// impl Hash for S { + /// fn hash(&self, state: &mut H) { + /// self.id.hash(state); + /// } + /// } + /// + /// let j_a = S { id: 1, name: "Jessica" }; + /// let j_b = S { id: 1, name: "Jess" }; + /// let p = S { id: 2, name: "Paul" }; + /// assert_eq!(j_a, j_b); + /// + /// let mut map = HashMap::new(); + /// map.insert(j_a, "Paris"); + /// assert_eq!(map.get_key_value(&j_a), Some((&j_a, &"Paris"))); + /// assert_eq!(map.get_key_value(&j_b), Some((&j_a, &"Paris"))); // the notable case + /// assert_eq!(map.get_key_value(&p), None); + /// ``` + #[inline] + #[stable(feature = "map_get_key_value", since = "1.40.0")] + pub fn get_key_value(&self, k: &Q) -> Option<(&K, &V)> + where + K: Borrow, + Q: Hash + Eq, + { + self.base.get_key_value(k) + } + + /// Attempts to get mutable references to `N` values in the map at once. + /// + /// Returns an array of length `N` with the results of each query. For soundness, at most one + /// mutable reference will be returned to any value. `None` will be used if the key is missing. + /// + /// This method performs a check to ensure there are no duplicate keys, which currently has a time-complexity of O(n^2), + /// so be careful when passing many keys. + /// + /// # Panics + /// + /// Panics if any keys are overlapping. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashMap; + /// + /// let mut libraries = HashMap::new(); + /// libraries.insert("Bodleian Library".to_string(), 1602); + /// libraries.insert("Athenæum".to_string(), 1807); + /// libraries.insert("Herzogin-Anna-Amalia-Bibliothek".to_string(), 1691); + /// libraries.insert("Library of Congress".to_string(), 1800); + /// + /// // Get Athenæum and Bodleian Library + /// let [Some(a), Some(b)] = libraries.get_disjoint_mut([ + /// "Athenæum", + /// "Bodleian Library", + /// ]) else { panic!() }; + /// + /// // Assert values of Athenæum and Library of Congress + /// let got = libraries.get_disjoint_mut([ + /// "Athenæum", + /// "Library of Congress", + /// ]); + /// assert_eq!( + /// got, + /// [ + /// Some(&mut 1807), + /// Some(&mut 1800), + /// ], + /// ); + /// + /// // Missing keys result in None + /// let got = libraries.get_disjoint_mut([ + /// "Athenæum", + /// "New York Public Library", + /// ]); + /// assert_eq!( + /// got, + /// [ + /// Some(&mut 1807), + /// None + /// ] + /// ); + /// ``` + /// + /// ```should_panic + /// use std::collections::HashMap; + /// + /// let mut libraries = HashMap::new(); + /// libraries.insert("Athenæum".to_string(), 1807); + /// + /// // Duplicate keys panic! + /// let got = libraries.get_disjoint_mut([ + /// "Athenæum", + /// "Athenæum", + /// ]); + /// ``` + #[inline] + #[doc(alias = "get_many_mut")] + #[stable(feature = "map_many_mut", since = "1.86.0")] + pub fn get_disjoint_mut( + &mut self, + ks: [&Q; N], + ) -> [Option<&'_ mut V>; N] + where + K: Borrow, + Q: Hash + Eq, + { + self.base.get_disjoint_mut(ks) + } + + /// Attempts to get mutable references to `N` values in the map at once, without validating that + /// the values are unique. + /// + /// Returns an array of length `N` with the results of each query. `None` will be used if + /// the key is missing. + /// + /// For a safe alternative see [`get_disjoint_mut`](`HashMap::get_disjoint_mut`). + /// + /// # Safety + /// + /// Calling this method with overlapping keys is *[undefined behavior]* even if the resulting + /// references are not used. + /// + /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashMap; + /// + /// let mut libraries = HashMap::new(); + /// libraries.insert("Bodleian Library".to_string(), 1602); + /// libraries.insert("Athenæum".to_string(), 1807); + /// libraries.insert("Herzogin-Anna-Amalia-Bibliothek".to_string(), 1691); + /// libraries.insert("Library of Congress".to_string(), 1800); + /// + /// // SAFETY: The keys do not overlap. + /// let [Some(a), Some(b)] = (unsafe { libraries.get_disjoint_unchecked_mut([ + /// "Athenæum", + /// "Bodleian Library", + /// ]) }) else { panic!() }; + /// + /// // SAFETY: The keys do not overlap. + /// let got = unsafe { libraries.get_disjoint_unchecked_mut([ + /// "Athenæum", + /// "Library of Congress", + /// ]) }; + /// assert_eq!( + /// got, + /// [ + /// Some(&mut 1807), + /// Some(&mut 1800), + /// ], + /// ); + /// + /// // SAFETY: The keys do not overlap. + /// let got = unsafe { libraries.get_disjoint_unchecked_mut([ + /// "Athenæum", + /// "New York Public Library", + /// ]) }; + /// // Missing keys result in None + /// assert_eq!(got, [Some(&mut 1807), None]); + /// ``` + #[inline] + #[doc(alias = "get_many_unchecked_mut")] + #[stable(feature = "map_many_mut", since = "1.86.0")] + pub unsafe fn get_disjoint_unchecked_mut( + &mut self, + ks: [&Q; N], + ) -> [Option<&'_ mut V>; N] + where + K: Borrow, + Q: Hash + Eq, + { + unsafe { self.base.get_disjoint_unchecked_mut(ks) } + } + + /// Returns `true` if the map contains a value for the specified key. + /// + /// The key may be any borrowed form of the map's key type, but + /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for + /// the key type. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashMap; + /// + /// let mut map = HashMap::new(); + /// map.insert(1, "a"); + /// assert_eq!(map.contains_key(&1), true); + /// assert_eq!(map.contains_key(&2), false); + /// ``` + #[inline] + #[stable(feature = "rust1", since = "1.0.0")] + #[cfg_attr(not(test), rustc_diagnostic_item = "hashmap_contains_key")] + pub fn contains_key(&self, k: &Q) -> bool + where + K: Borrow, + Q: Hash + Eq, + { + self.base.contains_key(k) + } + + /// Returns a mutable reference to the value corresponding to the key. + /// + /// The key may be any borrowed form of the map's key type, but + /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for + /// the key type. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashMap; + /// + /// let mut map = HashMap::new(); + /// map.insert(1, "a"); + /// if let Some(x) = map.get_mut(&1) { + /// *x = "b"; + /// } + /// assert_eq!(map[&1], "b"); + /// ``` + #[inline] + #[stable(feature = "rust1", since = "1.0.0")] + pub fn get_mut(&mut self, k: &Q) -> Option<&mut V> + where + K: Borrow, + Q: Hash + Eq, + { + self.base.get_mut(k) + } + + /// Inserts a key-value pair into the map. + /// + /// If the map did not have this key present, [`None`] is returned. + /// + /// If the map did have this key present, the value is updated, and the old + /// value is returned. The key is not updated, though; this matters for + /// types that can be `==` without being identical. See the [module-level + /// documentation] for more. + /// + /// [module-level documentation]: crate::collections#insert-and-complex-keys + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashMap; + /// + /// let mut map = HashMap::new(); + /// assert_eq!(map.insert(37, "a"), None); + /// assert_eq!(map.is_empty(), false); + /// + /// map.insert(37, "b"); + /// assert_eq!(map.insert(37, "c"), Some("b")); + /// assert_eq!(map[&37], "c"); + /// ``` + #[inline] + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_confusables("push", "append", "put")] + #[cfg_attr(not(test), rustc_diagnostic_item = "hashmap_insert")] + pub fn insert(&mut self, k: K, v: V) -> Option { + self.base.insert(k, v) + } + + /// Tries to insert a key-value pair into the map, and returns + /// a mutable reference to the value in the entry. + /// + /// If the map already had this key present, nothing is updated, and + /// an error containing the occupied entry and the value is returned. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(map_try_insert)] + /// + /// use std::collections::HashMap; + /// + /// let mut map = HashMap::new(); + /// assert_eq!(map.try_insert(37, "a").unwrap(), &"a"); + /// + /// let err = map.try_insert(37, "b").unwrap_err(); + /// assert_eq!(err.entry.key(), &37); + /// assert_eq!(err.entry.get(), &"a"); + /// assert_eq!(err.value, "b"); + /// ``` + #[unstable(feature = "map_try_insert", issue = "82766")] + pub fn try_insert(&mut self, key: K, value: V) -> Result<&mut V, OccupiedError<'_, K, V, A>> { + match self.entry(key) { + Occupied(entry) => Err(OccupiedError { entry, value }), + Vacant(entry) => Ok(entry.insert(value)), + } + } + + /// Removes a key from the map, returning the value at the key if the key + /// was previously in the map. + /// + /// The key may be any borrowed form of the map's key type, but + /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for + /// the key type. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashMap; + /// + /// let mut map = HashMap::new(); + /// map.insert(1, "a"); + /// assert_eq!(map.remove(&1), Some("a")); + /// assert_eq!(map.remove(&1), None); + /// ``` + #[inline] + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_confusables("delete", "take")] + pub fn remove(&mut self, k: &Q) -> Option + where + K: Borrow, + Q: Hash + Eq, + { + self.base.remove(k) + } + + /// Removes a key from the map, returning the stored key and value if the + /// key was previously in the map. + /// + /// The key may be any borrowed form of the map's key type, but + /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for + /// the key type. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashMap; + /// + /// # fn main() { + /// let mut map = HashMap::new(); + /// map.insert(1, "a"); + /// assert_eq!(map.remove_entry(&1), Some((1, "a"))); + /// assert_eq!(map.remove(&1), None); + /// # } + /// ``` + #[inline] + #[stable(feature = "hash_map_remove_entry", since = "1.27.0")] + pub fn remove_entry(&mut self, k: &Q) -> Option<(K, V)> + where + K: Borrow, + Q: Hash + Eq, + { + self.base.remove_entry(k) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Clone for HashMap +where + K: Clone, + V: Clone, + S: Clone, + A: Allocator + Clone, +{ + #[inline] + fn clone(&self) -> Self { + Self { base: self.base.clone() } + } + + #[inline] + fn clone_from(&mut self, source: &Self) { + self.base.clone_from(&source.base); + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl PartialEq for HashMap +where + K: Eq + Hash, + V: PartialEq, + S: BuildHasher, + A: Allocator, +{ + fn eq(&self, other: &HashMap) -> bool { + if self.len() != other.len() { + return false; + } + + self.iter().all(|(key, value)| other.get(key).map_or(false, |v| *value == *v)) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Eq for HashMap +where + K: Eq + Hash, + V: Eq, + S: BuildHasher, + A: Allocator, +{ +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Debug for HashMap +where + K: Debug, + V: Debug, + A: Allocator, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_map().entries(self.iter()).finish() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +#[rustc_const_unstable(feature = "const_default", issue = "143894")] +impl const Default for HashMap +where + S: [const] Default, +{ + /// Creates an empty `HashMap`, with the `Default` value for the hasher. + #[inline] + fn default() -> HashMap { + HashMap::with_hasher(Default::default()) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Index<&Q> for HashMap +where + K: Eq + Hash + Borrow, + Q: Eq + Hash, + S: BuildHasher, + A: Allocator, +{ + type Output = V; + + /// Returns a reference to the value corresponding to the supplied key. + /// + /// # Panics + /// + /// Panics if the key is not present in the `HashMap`. + #[inline] + fn index(&self, key: &Q) -> &V { + self.get(key).expect("no entry found for key") + } +} + +#[stable(feature = "std_collections_from_array", since = "1.56.0")] +// Note: as what is currently the most convenient built-in way to construct +// a HashMap, a simple usage of this function must not *require* the user +// to provide a type annotation in order to infer the third type parameter +// (the hasher parameter, conventionally "S"). +// To that end, this impl is defined using RandomState as the concrete +// type of S, rather than being generic over `S: BuildHasher + Default`. +// It is expected that users who want to specify a hasher will manually use +// `with_capacity_and_hasher`. +// If type parameter defaults worked on impls, and if type parameter +// defaults could be mixed with const generics, then perhaps +// this could be generalized. +// See also the equivalent impl on HashSet. +impl From<[(K, V); N]> for HashMap +where + K: Eq + Hash, +{ + /// Converts a `[(K, V); N]` into a `HashMap`. + /// + /// If any entries in the array have equal keys, + /// all but one of the corresponding values will be dropped. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashMap; + /// + /// let map1 = HashMap::from([(1, 2), (3, 4)]); + /// let map2: HashMap<_, _> = [(1, 2), (3, 4)].into(); + /// assert_eq!(map1, map2); + /// ``` + fn from(arr: [(K, V); N]) -> Self { + Self::from_iter(arr) + } +} + +/// An iterator over the entries of a `HashMap`. +/// +/// This `struct` is created by the [`iter`] method on [`HashMap`]. See its +/// documentation for more. +/// +/// [`iter`]: HashMap::iter +/// +/// # Example +/// +/// ``` +/// use std::collections::HashMap; +/// +/// let map = HashMap::from([ +/// ("a", 1), +/// ]); +/// let iter = map.iter(); +/// ``` +#[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr(not(test), rustc_diagnostic_item = "hashmap_iter_ty")] +pub struct Iter<'a, K: 'a, V: 'a> { + base: base::Iter<'a, K, V>, +} + +// FIXME(#26925) Remove in favor of `#[derive(Clone)]` +#[stable(feature = "rust1", since = "1.0.0")] +impl Clone for Iter<'_, K, V> { + #[inline] + fn clone(&self) -> Self { + Iter { base: self.base.clone() } + } +} + +#[stable(feature = "default_iters_hash", since = "1.83.0")] +impl Default for Iter<'_, K, V> { + #[inline] + fn default() -> Self { + Iter { base: Default::default() } + } +} + +#[stable(feature = "std_debug", since = "1.16.0")] +impl fmt::Debug for Iter<'_, K, V> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.clone()).finish() + } +} + +/// A mutable iterator over the entries of a `HashMap`. +/// +/// This `struct` is created by the [`iter_mut`] method on [`HashMap`]. See its +/// documentation for more. +/// +/// [`iter_mut`]: HashMap::iter_mut +/// +/// # Example +/// +/// ``` +/// use std::collections::HashMap; +/// +/// let mut map = HashMap::from([ +/// ("a", 1), +/// ]); +/// let iter = map.iter_mut(); +/// ``` +#[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr(not(test), rustc_diagnostic_item = "hashmap_iter_mut_ty")] +pub struct IterMut<'a, K: 'a, V: 'a> { + base: base::IterMut<'a, K, V>, +} + +impl<'a, K, V> IterMut<'a, K, V> { + /// Returns an iterator of references over the remaining items. + #[inline] + pub(super) fn iter(&self) -> Iter<'_, K, V> { + Iter { base: self.base.rustc_iter() } + } +} + +#[stable(feature = "default_iters_hash", since = "1.83.0")] +impl Default for IterMut<'_, K, V> { + #[inline] + fn default() -> Self { + IterMut { base: Default::default() } + } +} + +/// An owning iterator over the entries of a `HashMap`. +/// +/// This `struct` is created by the [`into_iter`] method on [`HashMap`] +/// (provided by the [`IntoIterator`] trait). See its documentation for more. +/// +/// [`into_iter`]: IntoIterator::into_iter +/// +/// # Example +/// +/// ``` +/// use std::collections::HashMap; +/// +/// let map = HashMap::from([ +/// ("a", 1), +/// ]); +/// let iter = map.into_iter(); +/// ``` +#[stable(feature = "rust1", since = "1.0.0")] +pub struct IntoIter< + K, + V, + #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, +> { + base: base::IntoIter, +} + +impl IntoIter { + /// Returns an iterator of references over the remaining items. + #[inline] + pub(super) fn iter(&self) -> Iter<'_, K, V> { + Iter { base: self.base.rustc_iter() } + } +} + +#[stable(feature = "default_iters_hash", since = "1.83.0")] +impl Default for IntoIter { + #[inline] + fn default() -> Self { + IntoIter { base: Default::default() } + } +} + +/// An iterator over the keys of a `HashMap`. +/// +/// This `struct` is created by the [`keys`] method on [`HashMap`]. See its +/// documentation for more. +/// +/// [`keys`]: HashMap::keys +/// +/// # Example +/// +/// ``` +/// use std::collections::HashMap; +/// +/// let map = HashMap::from([ +/// ("a", 1), +/// ]); +/// let iter_keys = map.keys(); +/// ``` +#[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr(not(test), rustc_diagnostic_item = "hashmap_keys_ty")] +pub struct Keys<'a, K: 'a, V: 'a> { + inner: Iter<'a, K, V>, +} + +// FIXME(#26925) Remove in favor of `#[derive(Clone)]` +#[stable(feature = "rust1", since = "1.0.0")] +impl Clone for Keys<'_, K, V> { + #[inline] + fn clone(&self) -> Self { + Keys { inner: self.inner.clone() } + } +} + +#[stable(feature = "default_iters_hash", since = "1.83.0")] +impl Default for Keys<'_, K, V> { + #[inline] + fn default() -> Self { + Keys { inner: Default::default() } + } +} + +#[stable(feature = "std_debug", since = "1.16.0")] +impl fmt::Debug for Keys<'_, K, V> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.clone()).finish() + } +} + +/// An iterator over the values of a `HashMap`. +/// +/// This `struct` is created by the [`values`] method on [`HashMap`]. See its +/// documentation for more. +/// +/// [`values`]: HashMap::values +/// +/// # Example +/// +/// ``` +/// use std::collections::HashMap; +/// +/// let map = HashMap::from([ +/// ("a", 1), +/// ]); +/// let iter_values = map.values(); +/// ``` +#[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr(not(test), rustc_diagnostic_item = "hashmap_values_ty")] +pub struct Values<'a, K: 'a, V: 'a> { + inner: Iter<'a, K, V>, +} + +// FIXME(#26925) Remove in favor of `#[derive(Clone)]` +#[stable(feature = "rust1", since = "1.0.0")] +impl Clone for Values<'_, K, V> { + #[inline] + fn clone(&self) -> Self { + Values { inner: self.inner.clone() } + } +} + +#[stable(feature = "default_iters_hash", since = "1.83.0")] +impl Default for Values<'_, K, V> { + #[inline] + fn default() -> Self { + Values { inner: Default::default() } + } +} + +#[stable(feature = "std_debug", since = "1.16.0")] +impl fmt::Debug for Values<'_, K, V> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.clone()).finish() + } +} + +/// A draining iterator over the entries of a `HashMap`. +/// +/// This `struct` is created by the [`drain`] method on [`HashMap`]. See its +/// documentation for more. +/// +/// [`drain`]: HashMap::drain +/// +/// # Example +/// +/// ``` +/// use std::collections::HashMap; +/// +/// let mut map = HashMap::from([ +/// ("a", 1), +/// ]); +/// let iter = map.drain(); +/// ``` +#[stable(feature = "drain", since = "1.6.0")] +#[cfg_attr(not(test), rustc_diagnostic_item = "hashmap_drain_ty")] +pub struct Drain< + 'a, + K: 'a, + V: 'a, + #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, +> { + base: base::Drain<'a, K, V, A>, +} + +impl<'a, K, V, A: Allocator> Drain<'a, K, V, A> { + /// Returns an iterator of references over the remaining items. + #[inline] + pub(super) fn iter(&self) -> Iter<'_, K, V> { + Iter { base: self.base.rustc_iter() } + } +} + +/// A draining, filtering iterator over the entries of a `HashMap`. +/// +/// This `struct` is created by the [`extract_if`] method on [`HashMap`]. +/// +/// [`extract_if`]: HashMap::extract_if +/// +/// # Example +/// +/// ``` +/// use std::collections::HashMap; +/// +/// let mut map = HashMap::from([ +/// ("a", 1), +/// ]); +/// let iter = map.extract_if(|_k, v| *v % 2 == 0); +/// ``` +#[stable(feature = "hash_extract_if", since = "1.88.0")] +#[must_use = "iterators are lazy and do nothing unless consumed; \ + use `retain` to remove and discard elements"] +pub struct ExtractIf< + 'a, + K, + V, + F, + #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, +> { + base: base::ExtractIf<'a, K, V, F, A>, +} + +/// A mutable iterator over the values of a `HashMap`. +/// +/// This `struct` is created by the [`values_mut`] method on [`HashMap`]. See its +/// documentation for more. +/// +/// [`values_mut`]: HashMap::values_mut +/// +/// # Example +/// +/// ``` +/// use std::collections::HashMap; +/// +/// let mut map = HashMap::from([ +/// ("a", 1), +/// ]); +/// let iter_values = map.values_mut(); +/// ``` +#[stable(feature = "map_values_mut", since = "1.10.0")] +#[cfg_attr(not(test), rustc_diagnostic_item = "hashmap_values_mut_ty")] +pub struct ValuesMut<'a, K: 'a, V: 'a> { + inner: IterMut<'a, K, V>, +} + +#[stable(feature = "default_iters_hash", since = "1.83.0")] +impl Default for ValuesMut<'_, K, V> { + #[inline] + fn default() -> Self { + ValuesMut { inner: Default::default() } + } +} + +/// An owning iterator over the keys of a `HashMap`. +/// +/// This `struct` is created by the [`into_keys`] method on [`HashMap`]. +/// See its documentation for more. +/// +/// [`into_keys`]: HashMap::into_keys +/// +/// # Example +/// +/// ``` +/// use std::collections::HashMap; +/// +/// let map = HashMap::from([ +/// ("a", 1), +/// ]); +/// let iter_keys = map.into_keys(); +/// ``` +#[stable(feature = "map_into_keys_values", since = "1.54.0")] +pub struct IntoKeys< + K, + V, + #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, +> { + inner: IntoIter, +} + +#[stable(feature = "default_iters_hash", since = "1.83.0")] +impl Default for IntoKeys { + #[inline] + fn default() -> Self { + IntoKeys { inner: Default::default() } + } +} + +/// An owning iterator over the values of a `HashMap`. +/// +/// This `struct` is created by the [`into_values`] method on [`HashMap`]. +/// See its documentation for more. +/// +/// [`into_values`]: HashMap::into_values +/// +/// # Example +/// +/// ``` +/// use std::collections::HashMap; +/// +/// let map = HashMap::from([ +/// ("a", 1), +/// ]); +/// let iter_keys = map.into_values(); +/// ``` +#[stable(feature = "map_into_keys_values", since = "1.54.0")] +pub struct IntoValues< + K, + V, + #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, +> { + inner: IntoIter, +} + +#[stable(feature = "default_iters_hash", since = "1.83.0")] +impl Default for IntoValues { + #[inline] + fn default() -> Self { + IntoValues { inner: Default::default() } + } +} + +/// A view into a single entry in a map, which may either be vacant or occupied. +/// +/// This `enum` is constructed from the [`entry`] method on [`HashMap`]. +/// +/// [`entry`]: HashMap::entry +#[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr(not(test), rustc_diagnostic_item = "HashMapEntry")] +pub enum Entry< + 'a, + K: 'a, + V: 'a, + #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, +> { + /// An occupied entry. + #[stable(feature = "rust1", since = "1.0.0")] + Occupied(#[stable(feature = "rust1", since = "1.0.0")] OccupiedEntry<'a, K, V, A>), + + /// A vacant entry. + #[stable(feature = "rust1", since = "1.0.0")] + Vacant(#[stable(feature = "rust1", since = "1.0.0")] VacantEntry<'a, K, V, A>), +} + +#[stable(feature = "debug_hash_map", since = "1.12.0")] +impl Debug for Entry<'_, K, V> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match *self { + Vacant(ref v) => f.debug_tuple("Entry").field(v).finish(), + Occupied(ref o) => f.debug_tuple("Entry").field(o).finish(), + } + } +} + +/// A view into an occupied entry in a `HashMap`. +/// It is part of the [`Entry`] enum. +#[stable(feature = "rust1", since = "1.0.0")] +pub struct OccupiedEntry< + 'a, + K: 'a, + V: 'a, + #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, +> { + base: base::RustcOccupiedEntry<'a, K, V, A>, +} + +#[stable(feature = "debug_hash_map", since = "1.12.0")] +impl Debug for OccupiedEntry<'_, K, V, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("OccupiedEntry") + .field("key", self.key()) + .field("value", self.get()) + .finish_non_exhaustive() + } +} + +/// A view into a vacant entry in a `HashMap`. +/// It is part of the [`Entry`] enum. +#[stable(feature = "rust1", since = "1.0.0")] +pub struct VacantEntry< + 'a, + K: 'a, + V: 'a, + #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, +> { + base: base::RustcVacantEntry<'a, K, V, A>, +} + +#[stable(feature = "debug_hash_map", since = "1.12.0")] +impl Debug for VacantEntry<'_, K, V, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_tuple("VacantEntry").field(self.key()).finish() + } +} + +/// The error returned by [`try_insert`](HashMap::try_insert) when the key already exists. +/// +/// Contains the occupied entry, and the value that was not inserted. +#[unstable(feature = "map_try_insert", issue = "82766")] +pub struct OccupiedError< + 'a, + K: 'a, + V: 'a, + #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, +> { + /// The entry in the map that was already occupied. + pub entry: OccupiedEntry<'a, K, V, A>, + /// The value which was not inserted, because the entry was already occupied. + pub value: V, +} + +#[unstable(feature = "map_try_insert", issue = "82766")] +impl Debug for OccupiedError<'_, K, V, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("OccupiedError") + .field("key", self.entry.key()) + .field("old_value", self.entry.get()) + .field("new_value", &self.value) + .finish_non_exhaustive() + } +} + +#[unstable(feature = "map_try_insert", issue = "82766")] +impl<'a, K: Debug, V: Debug, A: Allocator> fmt::Display for OccupiedError<'a, K, V, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "failed to insert {:?}, key {:?} already exists with value {:?}", + self.value, + self.entry.key(), + self.entry.get(), + ) + } +} + +#[unstable(feature = "map_try_insert", issue = "82766")] +impl<'a, K: Debug, V: Debug, A: Allocator> Error for OccupiedError<'a, K, V, A> {} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, K, V, S, A: Allocator> IntoIterator for &'a HashMap { + type Item = (&'a K, &'a V); + type IntoIter = Iter<'a, K, V>; + + #[inline] + #[rustc_lint_query_instability] + fn into_iter(self) -> Iter<'a, K, V> { + self.iter() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, K, V, S, A: Allocator> IntoIterator for &'a mut HashMap { + type Item = (&'a K, &'a mut V); + type IntoIter = IterMut<'a, K, V>; + + #[inline] + #[rustc_lint_query_instability] + fn into_iter(self) -> IterMut<'a, K, V> { + self.iter_mut() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl IntoIterator for HashMap { + type Item = (K, V); + type IntoIter = IntoIter; + + /// Creates a consuming iterator, that is, one that moves each key-value + /// pair out of the map in arbitrary order. The map cannot be used after + /// calling this. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashMap; + /// + /// let map = HashMap::from([ + /// ("a", 1), + /// ("b", 2), + /// ("c", 3), + /// ]); + /// + /// // Not possible with .iter() + /// let vec: Vec<(&str, i32)> = map.into_iter().collect(); + /// ``` + #[inline] + #[rustc_lint_query_instability] + fn into_iter(self) -> IntoIter { + IntoIter { base: self.base.into_iter() } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, K, V> Iterator for Iter<'a, K, V> { + type Item = (&'a K, &'a V); + + #[inline] + fn next(&mut self) -> Option<(&'a K, &'a V)> { + self.base.next() + } + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.base.size_hint() + } + #[inline] + fn count(self) -> usize { + self.base.len() + } + #[inline] + fn fold(self, init: B, f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.base.fold(init, f) + } +} +#[stable(feature = "rust1", since = "1.0.0")] +impl ExactSizeIterator for Iter<'_, K, V> { + #[inline] + fn len(&self) -> usize { + self.base.len() + } +} + +#[stable(feature = "fused", since = "1.26.0")] +impl FusedIterator for Iter<'_, K, V> {} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, K, V> Iterator for IterMut<'a, K, V> { + type Item = (&'a K, &'a mut V); + + #[inline] + fn next(&mut self) -> Option<(&'a K, &'a mut V)> { + self.base.next() + } + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.base.size_hint() + } + #[inline] + fn count(self) -> usize { + self.base.len() + } + #[inline] + fn fold(self, init: B, f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.base.fold(init, f) + } +} +#[stable(feature = "rust1", since = "1.0.0")] +impl ExactSizeIterator for IterMut<'_, K, V> { + #[inline] + fn len(&self) -> usize { + self.base.len() + } +} +#[stable(feature = "fused", since = "1.26.0")] +impl FusedIterator for IterMut<'_, K, V> {} + +#[stable(feature = "std_debug", since = "1.16.0")] +impl fmt::Debug for IterMut<'_, K, V> +where + K: fmt::Debug, + V: fmt::Debug, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.iter()).finish() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Iterator for IntoIter { + type Item = (K, V); + + #[inline] + fn next(&mut self) -> Option<(K, V)> { + self.base.next() + } + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.base.size_hint() + } + #[inline] + fn count(self) -> usize { + self.base.len() + } + #[inline] + fn fold(self, init: B, f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.base.fold(init, f) + } +} +#[stable(feature = "rust1", since = "1.0.0")] +impl ExactSizeIterator for IntoIter { + #[inline] + fn len(&self) -> usize { + self.base.len() + } +} +#[stable(feature = "fused", since = "1.26.0")] +impl FusedIterator for IntoIter {} + +#[stable(feature = "std_debug", since = "1.16.0")] +impl fmt::Debug for IntoIter { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.iter()).finish() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, K, V> Iterator for Keys<'a, K, V> { + type Item = &'a K; + + #[inline] + fn next(&mut self) -> Option<&'a K> { + self.inner.next().map(|(k, _)| k) + } + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.inner.size_hint() + } + #[inline] + fn count(self) -> usize { + self.inner.len() + } + #[inline] + fn fold(self, init: B, mut f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.inner.fold(init, |acc, (k, _)| f(acc, k)) + } +} +#[stable(feature = "rust1", since = "1.0.0")] +impl ExactSizeIterator for Keys<'_, K, V> { + #[inline] + fn len(&self) -> usize { + self.inner.len() + } +} +#[stable(feature = "fused", since = "1.26.0")] +impl FusedIterator for Keys<'_, K, V> {} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, K, V> Iterator for Values<'a, K, V> { + type Item = &'a V; + + #[inline] + fn next(&mut self) -> Option<&'a V> { + self.inner.next().map(|(_, v)| v) + } + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.inner.size_hint() + } + #[inline] + fn count(self) -> usize { + self.inner.len() + } + #[inline] + fn fold(self, init: B, mut f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.inner.fold(init, |acc, (_, v)| f(acc, v)) + } +} +#[stable(feature = "rust1", since = "1.0.0")] +impl ExactSizeIterator for Values<'_, K, V> { + #[inline] + fn len(&self) -> usize { + self.inner.len() + } +} +#[stable(feature = "fused", since = "1.26.0")] +impl FusedIterator for Values<'_, K, V> {} + +#[stable(feature = "map_values_mut", since = "1.10.0")] +impl<'a, K, V> Iterator for ValuesMut<'a, K, V> { + type Item = &'a mut V; + + #[inline] + fn next(&mut self) -> Option<&'a mut V> { + self.inner.next().map(|(_, v)| v) + } + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.inner.size_hint() + } + #[inline] + fn count(self) -> usize { + self.inner.len() + } + #[inline] + fn fold(self, init: B, mut f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.inner.fold(init, |acc, (_, v)| f(acc, v)) + } +} +#[stable(feature = "map_values_mut", since = "1.10.0")] +impl ExactSizeIterator for ValuesMut<'_, K, V> { + #[inline] + fn len(&self) -> usize { + self.inner.len() + } +} +#[stable(feature = "fused", since = "1.26.0")] +impl FusedIterator for ValuesMut<'_, K, V> {} + +#[stable(feature = "std_debug", since = "1.16.0")] +impl fmt::Debug for ValuesMut<'_, K, V> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.inner.iter().map(|(_, val)| val)).finish() + } +} + +#[stable(feature = "map_into_keys_values", since = "1.54.0")] +impl Iterator for IntoKeys { + type Item = K; + + #[inline] + fn next(&mut self) -> Option { + self.inner.next().map(|(k, _)| k) + } + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.inner.size_hint() + } + #[inline] + fn count(self) -> usize { + self.inner.len() + } + #[inline] + fn fold(self, init: B, mut f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.inner.fold(init, |acc, (k, _)| f(acc, k)) + } +} +#[stable(feature = "map_into_keys_values", since = "1.54.0")] +impl ExactSizeIterator for IntoKeys { + #[inline] + fn len(&self) -> usize { + self.inner.len() + } +} +#[stable(feature = "map_into_keys_values", since = "1.54.0")] +impl FusedIterator for IntoKeys {} + +#[stable(feature = "map_into_keys_values", since = "1.54.0")] +impl fmt::Debug for IntoKeys { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.inner.iter().map(|(k, _)| k)).finish() + } +} + +#[stable(feature = "map_into_keys_values", since = "1.54.0")] +impl Iterator for IntoValues { + type Item = V; + + #[inline] + fn next(&mut self) -> Option { + self.inner.next().map(|(_, v)| v) + } + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.inner.size_hint() + } + #[inline] + fn count(self) -> usize { + self.inner.len() + } + #[inline] + fn fold(self, init: B, mut f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.inner.fold(init, |acc, (_, v)| f(acc, v)) + } +} +#[stable(feature = "map_into_keys_values", since = "1.54.0")] +impl ExactSizeIterator for IntoValues { + #[inline] + fn len(&self) -> usize { + self.inner.len() + } +} +#[stable(feature = "map_into_keys_values", since = "1.54.0")] +impl FusedIterator for IntoValues {} + +#[stable(feature = "map_into_keys_values", since = "1.54.0")] +impl fmt::Debug for IntoValues { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.inner.iter().map(|(_, v)| v)).finish() + } +} + +#[stable(feature = "drain", since = "1.6.0")] +impl<'a, K, V, A: Allocator> Iterator for Drain<'a, K, V, A> { + type Item = (K, V); + + #[inline] + fn next(&mut self) -> Option<(K, V)> { + self.base.next() + } + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.base.size_hint() + } + #[inline] + fn fold(self, init: B, f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.base.fold(init, f) + } +} +#[stable(feature = "drain", since = "1.6.0")] +impl ExactSizeIterator for Drain<'_, K, V, A> { + #[inline] + fn len(&self) -> usize { + self.base.len() + } +} +#[stable(feature = "fused", since = "1.26.0")] +impl FusedIterator for Drain<'_, K, V, A> {} + +#[stable(feature = "std_debug", since = "1.16.0")] +impl fmt::Debug for Drain<'_, K, V, A> +where + K: fmt::Debug, + V: fmt::Debug, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.iter()).finish() + } +} + +#[stable(feature = "hash_extract_if", since = "1.88.0")] +impl Iterator for ExtractIf<'_, K, V, F, A> +where + F: FnMut(&K, &mut V) -> bool, +{ + type Item = (K, V); + + #[inline] + fn next(&mut self) -> Option<(K, V)> { + self.base.next() + } + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.base.size_hint() + } +} + +#[stable(feature = "hash_extract_if", since = "1.88.0")] +impl FusedIterator for ExtractIf<'_, K, V, F, A> where + F: FnMut(&K, &mut V) -> bool +{ +} + +#[stable(feature = "hash_extract_if", since = "1.88.0")] +impl fmt::Debug for ExtractIf<'_, K, V, F, A> +where + K: fmt::Debug, + V: fmt::Debug, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("ExtractIf").finish_non_exhaustive() + } +} + +impl<'a, K, V, A: Allocator> Entry<'a, K, V, A> { + /// Ensures a value is in the entry by inserting the default if empty, and returns + /// a mutable reference to the value in the entry. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashMap; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// + /// map.entry("poneyland").or_insert(3); + /// assert_eq!(map["poneyland"], 3); + /// + /// *map.entry("poneyland").or_insert(10) *= 2; + /// assert_eq!(map["poneyland"], 6); + /// ``` + #[inline] + #[stable(feature = "rust1", since = "1.0.0")] + pub fn or_insert(self, default: V) -> &'a mut V { + match self { + Occupied(entry) => entry.into_mut(), + Vacant(entry) => entry.insert(default), + } + } + + /// Ensures a value is in the entry by inserting the result of the default function if empty, + /// and returns a mutable reference to the value in the entry. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashMap; + /// + /// let mut map = HashMap::new(); + /// let value = "hoho"; + /// + /// map.entry("poneyland").or_insert_with(|| value); + /// + /// assert_eq!(map["poneyland"], "hoho"); + /// ``` + #[inline] + #[stable(feature = "rust1", since = "1.0.0")] + pub fn or_insert_with V>(self, default: F) -> &'a mut V { + match self { + Occupied(entry) => entry.into_mut(), + Vacant(entry) => entry.insert(default()), + } + } + + /// Ensures a value is in the entry by inserting, if empty, the result of the default function. + /// This method allows for generating key-derived values for insertion by providing the default + /// function a reference to the key that was moved during the `.entry(key)` method call. + /// + /// The reference to the moved key is provided so that cloning or copying the key is + /// unnecessary, unlike with `.or_insert_with(|| ... )`. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashMap; + /// + /// let mut map: HashMap<&str, usize> = HashMap::new(); + /// + /// map.entry("poneyland").or_insert_with_key(|key| key.chars().count()); + /// + /// assert_eq!(map["poneyland"], 9); + /// ``` + #[inline] + #[stable(feature = "or_insert_with_key", since = "1.50.0")] + pub fn or_insert_with_key V>(self, default: F) -> &'a mut V { + match self { + Occupied(entry) => entry.into_mut(), + Vacant(entry) => { + let value = default(entry.key()); + entry.insert(value) + } + } + } + + /// Returns a reference to this entry's key. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashMap; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// assert_eq!(map.entry("poneyland").key(), &"poneyland"); + /// ``` + #[inline] + #[stable(feature = "map_entry_keys", since = "1.10.0")] + pub fn key(&self) -> &K { + match *self { + Occupied(ref entry) => entry.key(), + Vacant(ref entry) => entry.key(), + } + } + + /// Provides in-place mutable access to an occupied entry before any + /// potential inserts into the map. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashMap; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// + /// map.entry("poneyland") + /// .and_modify(|e| { *e += 1 }) + /// .or_insert(42); + /// assert_eq!(map["poneyland"], 42); + /// + /// map.entry("poneyland") + /// .and_modify(|e| { *e += 1 }) + /// .or_insert(42); + /// assert_eq!(map["poneyland"], 43); + /// ``` + #[inline] + #[stable(feature = "entry_and_modify", since = "1.26.0")] + pub fn and_modify(self, f: F) -> Self + where + F: FnOnce(&mut V), + { + match self { + Occupied(mut entry) => { + f(entry.get_mut()); + Occupied(entry) + } + Vacant(entry) => Vacant(entry), + } + } + + /// Sets the value of the entry, and returns an `OccupiedEntry`. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashMap; + /// + /// let mut map: HashMap<&str, String> = HashMap::new(); + /// let entry = map.entry("poneyland").insert_entry("hoho".to_string()); + /// + /// assert_eq!(entry.key(), &"poneyland"); + /// ``` + #[inline] + #[stable(feature = "entry_insert", since = "1.83.0")] + pub fn insert_entry(self, value: V) -> OccupiedEntry<'a, K, V, A> { + match self { + Occupied(mut entry) => { + entry.insert(value); + entry + } + Vacant(entry) => entry.insert_entry(value), + } + } +} + +impl<'a, K, V: Default> Entry<'a, K, V> { + /// Ensures a value is in the entry by inserting the default value if empty, + /// and returns a mutable reference to the value in the entry. + /// + /// # Examples + /// + /// ``` + /// # fn main() { + /// use std::collections::HashMap; + /// + /// let mut map: HashMap<&str, Option> = HashMap::new(); + /// map.entry("poneyland").or_default(); + /// + /// assert_eq!(map["poneyland"], None); + /// # } + /// ``` + #[inline] + #[stable(feature = "entry_or_default", since = "1.28.0")] + pub fn or_default(self) -> &'a mut V { + match self { + Occupied(entry) => entry.into_mut(), + Vacant(entry) => entry.insert(Default::default()), + } + } +} + +impl<'a, K, V, A: Allocator> OccupiedEntry<'a, K, V, A> { + /// Gets a reference to the key in the entry. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashMap; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// map.entry("poneyland").or_insert(12); + /// assert_eq!(map.entry("poneyland").key(), &"poneyland"); + /// ``` + #[inline] + #[stable(feature = "map_entry_keys", since = "1.10.0")] + pub fn key(&self) -> &K { + self.base.key() + } + + /// Take the ownership of the key and value from the map. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashMap; + /// use std::collections::hash_map::Entry; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// map.entry("poneyland").or_insert(12); + /// + /// if let Entry::Occupied(o) = map.entry("poneyland") { + /// // We delete the entry from the map. + /// o.remove_entry(); + /// } + /// + /// assert_eq!(map.contains_key("poneyland"), false); + /// ``` + #[inline] + #[stable(feature = "map_entry_recover_keys2", since = "1.12.0")] + pub fn remove_entry(self) -> (K, V) { + self.base.remove_entry() + } + + /// Gets a reference to the value in the entry. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashMap; + /// use std::collections::hash_map::Entry; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// map.entry("poneyland").or_insert(12); + /// + /// if let Entry::Occupied(o) = map.entry("poneyland") { + /// assert_eq!(o.get(), &12); + /// } + /// ``` + #[inline] + #[stable(feature = "rust1", since = "1.0.0")] + pub fn get(&self) -> &V { + self.base.get() + } + + /// Gets a mutable reference to the value in the entry. + /// + /// If you need a reference to the `OccupiedEntry` which may outlive the + /// destruction of the `Entry` value, see [`into_mut`]. + /// + /// [`into_mut`]: Self::into_mut + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashMap; + /// use std::collections::hash_map::Entry; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// map.entry("poneyland").or_insert(12); + /// + /// assert_eq!(map["poneyland"], 12); + /// if let Entry::Occupied(mut o) = map.entry("poneyland") { + /// *o.get_mut() += 10; + /// assert_eq!(*o.get(), 22); + /// + /// // We can use the same Entry multiple times. + /// *o.get_mut() += 2; + /// } + /// + /// assert_eq!(map["poneyland"], 24); + /// ``` + #[inline] + #[stable(feature = "rust1", since = "1.0.0")] + pub fn get_mut(&mut self) -> &mut V { + self.base.get_mut() + } + + /// Converts the `OccupiedEntry` into a mutable reference to the value in the entry + /// with a lifetime bound to the map itself. + /// + /// If you need multiple references to the `OccupiedEntry`, see [`get_mut`]. + /// + /// [`get_mut`]: Self::get_mut + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashMap; + /// use std::collections::hash_map::Entry; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// map.entry("poneyland").or_insert(12); + /// + /// assert_eq!(map["poneyland"], 12); + /// if let Entry::Occupied(o) = map.entry("poneyland") { + /// *o.into_mut() += 10; + /// } + /// + /// assert_eq!(map["poneyland"], 22); + /// ``` + #[inline] + #[stable(feature = "rust1", since = "1.0.0")] + pub fn into_mut(self) -> &'a mut V { + self.base.into_mut() + } + + /// Sets the value of the entry, and returns the entry's old value. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashMap; + /// use std::collections::hash_map::Entry; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// map.entry("poneyland").or_insert(12); + /// + /// if let Entry::Occupied(mut o) = map.entry("poneyland") { + /// assert_eq!(o.insert(15), 12); + /// } + /// + /// assert_eq!(map["poneyland"], 15); + /// ``` + #[inline] + #[stable(feature = "rust1", since = "1.0.0")] + pub fn insert(&mut self, value: V) -> V { + self.base.insert(value) + } + + /// Takes the value out of the entry, and returns it. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashMap; + /// use std::collections::hash_map::Entry; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// map.entry("poneyland").or_insert(12); + /// + /// if let Entry::Occupied(o) = map.entry("poneyland") { + /// assert_eq!(o.remove(), 12); + /// } + /// + /// assert_eq!(map.contains_key("poneyland"), false); + /// ``` + #[inline] + #[stable(feature = "rust1", since = "1.0.0")] + pub fn remove(self) -> V { + self.base.remove() + } +} + +impl<'a, K: 'a, V: 'a, A: Allocator> VacantEntry<'a, K, V, A> { + /// Gets a reference to the key that would be used when inserting a value + /// through the `VacantEntry`. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashMap; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// assert_eq!(map.entry("poneyland").key(), &"poneyland"); + /// ``` + #[inline] + #[stable(feature = "map_entry_keys", since = "1.10.0")] + pub fn key(&self) -> &K { + self.base.key() + } + + /// Take ownership of the key. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashMap; + /// use std::collections::hash_map::Entry; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// + /// if let Entry::Vacant(v) = map.entry("poneyland") { + /// v.into_key(); + /// } + /// ``` + #[inline] + #[stable(feature = "map_entry_recover_keys2", since = "1.12.0")] + pub fn into_key(self) -> K { + self.base.into_key() + } + + /// Sets the value of the entry with the `VacantEntry`'s key, + /// and returns a mutable reference to it. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashMap; + /// use std::collections::hash_map::Entry; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// + /// if let Entry::Vacant(o) = map.entry("poneyland") { + /// o.insert(37); + /// } + /// assert_eq!(map["poneyland"], 37); + /// ``` + #[inline] + #[stable(feature = "rust1", since = "1.0.0")] + pub fn insert(self, value: V) -> &'a mut V { + self.base.insert(value) + } + + /// Sets the value of the entry with the `VacantEntry`'s key, + /// and returns an `OccupiedEntry`. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashMap; + /// use std::collections::hash_map::Entry; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// + /// if let Entry::Vacant(o) = map.entry("poneyland") { + /// o.insert_entry(37); + /// } + /// assert_eq!(map["poneyland"], 37); + /// ``` + #[inline] + #[stable(feature = "entry_insert", since = "1.83.0")] + pub fn insert_entry(self, value: V) -> OccupiedEntry<'a, K, V, A> { + let base = self.base.insert_entry(value); + OccupiedEntry { base } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl FromIterator<(K, V)> for HashMap +where + K: Eq + Hash, + S: BuildHasher + Default, +{ + /// Constructs a `HashMap` from an iterator of key-value pairs. + /// + /// If the iterator produces any pairs with equal keys, + /// all but one of the corresponding values will be dropped. + fn from_iter>(iter: T) -> HashMap { + let mut map = HashMap::with_hasher(Default::default()); + map.extend(iter); + map + } +} + +/// Inserts all new key-values from the iterator and replaces values with existing +/// keys with new values returned from the iterator. +#[stable(feature = "rust1", since = "1.0.0")] +impl Extend<(K, V)> for HashMap +where + K: Eq + Hash, + S: BuildHasher, + A: Allocator, +{ + #[inline] + fn extend>(&mut self, iter: T) { + self.base.extend(iter) + } + + #[inline] + fn extend_one(&mut self, (k, v): (K, V)) { + self.base.insert(k, v); + } + + #[inline] + fn extend_reserve(&mut self, additional: usize) { + self.base.extend_reserve(additional); + } +} + +#[stable(feature = "hash_extend_copy", since = "1.4.0")] +impl<'a, K, V, S, A> Extend<(&'a K, &'a V)> for HashMap +where + K: Eq + Hash + Copy, + V: Copy, + S: BuildHasher, + A: Allocator, +{ + #[inline] + fn extend>(&mut self, iter: T) { + self.base.extend(iter) + } + + #[inline] + fn extend_one(&mut self, (&k, &v): (&'a K, &'a V)) { + self.base.insert(k, v); + } + + #[inline] + fn extend_reserve(&mut self, additional: usize) { + Extend::<(K, V)>::extend_reserve(self, additional) + } +} + +#[inline] +fn map_entry<'a, K: 'a, V: 'a, A: Allocator>( + raw: base::RustcEntry<'a, K, V, A>, +) -> Entry<'a, K, V, A> { + match raw { + base::RustcEntry::Occupied(base) => Entry::Occupied(OccupiedEntry { base }), + base::RustcEntry::Vacant(base) => Entry::Vacant(VacantEntry { base }), + } +} + +#[inline] +pub(super) fn map_try_reserve_error(err: hashbrown::TryReserveError) -> TryReserveError { + match err { + hashbrown::TryReserveError::CapacityOverflow => { + TryReserveErrorKind::CapacityOverflow.into() + } + hashbrown::TryReserveError::AllocError { layout } => { + TryReserveErrorKind::AllocError { layout, non_exhaustive: () }.into() + } + } +} + +#[allow(dead_code)] +fn assert_covariance() { + fn map_key<'new>(v: HashMap<&'static str, u8>) -> HashMap<&'new str, u8> { + v + } + fn map_val<'new>(v: HashMap) -> HashMap { + v + } + fn iter_key<'a, 'new>(v: Iter<'a, &'static str, u8>) -> Iter<'a, &'new str, u8> { + v + } + fn iter_val<'a, 'new>(v: Iter<'a, u8, &'static str>) -> Iter<'a, u8, &'new str> { + v + } + fn into_iter_key<'new>(v: IntoIter<&'static str, u8>) -> IntoIter<&'new str, u8> { + v + } + fn into_iter_val<'new>(v: IntoIter) -> IntoIter { + v + } + fn keys_key<'a, 'new>(v: Keys<'a, &'static str, u8>) -> Keys<'a, &'new str, u8> { + v + } + fn keys_val<'a, 'new>(v: Keys<'a, u8, &'static str>) -> Keys<'a, u8, &'new str> { + v + } + fn values_key<'a, 'new>(v: Values<'a, &'static str, u8>) -> Values<'a, &'new str, u8> { + v + } + fn values_val<'a, 'new>(v: Values<'a, u8, &'static str>) -> Values<'a, u8, &'new str> { + v + } + fn drain<'new>( + d: Drain<'static, &'static str, &'static str>, + ) -> Drain<'new, &'new str, &'new str> { + d + } +} diff --git a/crates/std/src/collections/hash/mod.rs b/crates/std/src/collections/hash/mod.rs new file mode 100644 index 0000000..348820a --- /dev/null +++ b/crates/std/src/collections/hash/mod.rs @@ -0,0 +1,4 @@ +//! Unordered containers, implemented as hash-tables + +pub mod map; +pub mod set; diff --git a/crates/std/src/collections/hash/set.rs b/crates/std/src/collections/hash/set.rs new file mode 100644 index 0000000..6d6479f --- /dev/null +++ b/crates/std/src/collections/hash/set.rs @@ -0,0 +1,2515 @@ +#[cfg(test)] +mod tests; + +use hashbrown::hash_set as base; + +use super::map::map_try_reserve_error; +use crate::alloc::{Allocator, Global}; +use crate::borrow::Borrow; +use alloc_crate::collections::TryReserveError; +use crate::fmt; +use crate::hash::{BuildHasher, Hash, RandomState}; +use crate::iter::{Chain, FusedIterator}; +use crate::ops::{BitAnd, BitOr, BitXor, Sub}; + +/// A [hash set] implemented as a `HashMap` where the value is `()`. +/// +/// As with the [`HashMap`] type, a `HashSet` requires that the elements +/// implement the [`Eq`] and [`Hash`] traits. This can frequently be achieved by +/// using `#[derive(PartialEq, Eq, Hash)]`. If you implement these yourself, +/// it is important that the following property holds: +/// +/// ```text +/// k1 == k2 -> hash(k1) == hash(k2) +/// ``` +/// +/// In other words, if two keys are equal, their hashes must be equal. +/// Violating this property is a logic error. +/// +/// It is also a logic error for a key to be modified in such a way that the key's +/// hash, as determined by the [`Hash`] trait, or its equality, as determined by +/// the [`Eq`] trait, changes while it is in the map. This is normally only +/// possible through [`Cell`], [`RefCell`], global state, I/O, or unsafe code. +/// +/// The behavior resulting from either logic error is not specified, but will +/// be encapsulated to the `HashSet` that observed the logic error and not +/// result in undefined behavior. This could include panics, incorrect results, +/// aborts, memory leaks, and non-termination. +/// +/// # Examples +/// +/// ``` +/// use std::collections::HashSet; +/// // Type inference lets us omit an explicit type signature (which +/// // would be `HashSet` in this example). +/// let mut books = HashSet::new(); +/// +/// // Add some books. +/// books.insert("A Dance With Dragons".to_string()); +/// books.insert("To Kill a Mockingbird".to_string()); +/// books.insert("The Odyssey".to_string()); +/// books.insert("The Great Gatsby".to_string()); +/// +/// // Check for a specific one. +/// if !books.contains("The Winds of Winter") { +/// println!("We have {} books, but The Winds of Winter ain't one.", +/// books.len()); +/// } +/// +/// // Remove a book. +/// books.remove("The Odyssey"); +/// +/// // Iterate over everything. +/// for book in &books { +/// println!("{book}"); +/// } +/// ``` +/// +/// The easiest way to use `HashSet` with a custom type is to derive +/// [`Eq`] and [`Hash`]. We must also derive [`PartialEq`], +/// which is required if [`Eq`] is derived. +/// +/// ``` +/// use std::collections::HashSet; +/// #[derive(Hash, Eq, PartialEq, Debug)] +/// struct Viking { +/// name: String, +/// power: usize, +/// } +/// +/// let mut vikings = HashSet::new(); +/// +/// vikings.insert(Viking { name: "Einar".to_string(), power: 9 }); +/// vikings.insert(Viking { name: "Einar".to_string(), power: 9 }); +/// vikings.insert(Viking { name: "Olaf".to_string(), power: 4 }); +/// vikings.insert(Viking { name: "Harald".to_string(), power: 8 }); +/// +/// // Use derived implementation to print the vikings. +/// for x in &vikings { +/// println!("{x:?}"); +/// } +/// ``` +/// +/// A `HashSet` with a known list of items can be initialized from an array: +/// +/// ``` +/// use std::collections::HashSet; +/// +/// let viking_names = HashSet::from(["Einar", "Olaf", "Harald"]); +/// ``` +/// +/// [hash set]: crate::collections#use-the-set-variant-of-any-of-these-maps-when +/// [`HashMap`]: crate::collections::HashMap +/// [`RefCell`]: crate::cell::RefCell +/// [`Cell`]: crate::cell::Cell +/// +/// # Usage in `const` and `static` +/// +/// Like `HashMap`, `HashSet` is randomly seeded: each `HashSet` instance uses a different seed, +/// which means that `HashSet::new` cannot be used in const context. To construct a `HashSet` in the +/// initializer of a `const` or `static` item, you will have to use a different hasher that does not +/// involve a random seed, as demonstrated in the following example. **A `HashSet` constructed this +/// way is not resistant against HashDoS!** +/// +/// ```rust +/// use std::collections::HashSet; +/// use std::hash::{BuildHasherDefault, DefaultHasher}; +/// use std::sync::Mutex; +/// +/// const EMPTY_SET: HashSet> = +/// HashSet::with_hasher(BuildHasherDefault::new()); +/// static SET: Mutex>> = +/// Mutex::new(HashSet::with_hasher(BuildHasherDefault::new())); +/// ``` +#[cfg_attr(not(test), rustc_diagnostic_item = "HashSet")] +#[stable(feature = "rust1", since = "1.0.0")] +pub struct HashSet< + T, + S = RandomState, + #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, +> { + base: base::HashSet, +} + +impl HashSet { + /// Creates an empty `HashSet`. + /// + /// The hash set is initially created with a capacity of 0, so it will not allocate until it + /// is first inserted into. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashSet; + /// let set: HashSet = HashSet::new(); + /// ``` + #[inline] + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + pub fn new() -> HashSet { + Default::default() + } + + /// Creates an empty `HashSet` with at least the specified capacity. + /// + /// The hash set will be able to hold at least `capacity` elements without + /// reallocating. This method is allowed to allocate for more elements than + /// `capacity`. If `capacity` is zero, the hash set will not allocate. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashSet; + /// let set: HashSet = HashSet::with_capacity(10); + /// assert!(set.capacity() >= 10); + /// ``` + #[inline] + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + pub fn with_capacity(capacity: usize) -> HashSet { + HashSet::with_capacity_and_hasher(capacity, Default::default()) + } +} + +impl HashSet { + /// Creates an empty `HashSet` in the provided allocator. + /// + /// The hash set is initially created with a capacity of 0, so it will not allocate until it + /// is first inserted into. + #[inline] + #[must_use] + #[unstable(feature = "allocator_api", issue = "32838")] + pub fn new_in(alloc: A) -> HashSet { + HashSet::with_hasher_in(Default::default(), alloc) + } + + /// Creates an empty `HashSet` with at least the specified capacity. + /// + /// The hash set will be able to hold at least `capacity` elements without + /// reallocating. This method is allowed to allocate for more elements than + /// `capacity`. If `capacity` is zero, the hash set will not allocate. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashSet; + /// let set: HashSet = HashSet::with_capacity(10); + /// assert!(set.capacity() >= 10); + /// ``` + #[inline] + #[must_use] + #[unstable(feature = "allocator_api", issue = "32838")] + pub fn with_capacity_in(capacity: usize, alloc: A) -> HashSet { + HashSet::with_capacity_and_hasher_in(capacity, Default::default(), alloc) + } +} + +impl HashSet { + /// Creates a new empty hash set which will use the given hasher to hash + /// keys. + /// + /// The hash set is also created with the default initial capacity. + /// + /// Warning: `hasher` is normally randomly generated, and + /// is designed to allow `HashSet`s to be resistant to attacks that + /// cause many collisions and very poor performance. Setting it + /// manually using this function can expose a DoS attack vector. + /// + /// The `hash_builder` passed should implement the [`BuildHasher`] trait for + /// the `HashSet` to be useful, see its documentation for details. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashSet; + /// use std::hash::RandomState; + /// + /// let s = RandomState::new(); + /// let mut set = HashSet::with_hasher(s); + /// set.insert(2); + /// ``` + #[inline] + #[stable(feature = "hashmap_build_hasher", since = "1.7.0")] + #[rustc_const_stable(feature = "const_collections_with_hasher", since = "1.85.0")] + pub const fn with_hasher(hasher: S) -> HashSet { + HashSet { base: base::HashSet::with_hasher(hasher) } + } + + /// Creates an empty `HashSet` with at least the specified capacity, using + /// `hasher` to hash the keys. + /// + /// The hash set will be able to hold at least `capacity` elements without + /// reallocating. This method is allowed to allocate for more elements than + /// `capacity`. If `capacity` is zero, the hash set will not allocate. + /// + /// Warning: `hasher` is normally randomly generated, and + /// is designed to allow `HashSet`s to be resistant to attacks that + /// cause many collisions and very poor performance. Setting it + /// manually using this function can expose a DoS attack vector. + /// + /// The `hash_builder` passed should implement the [`BuildHasher`] trait for + /// the `HashSet` to be useful, see its documentation for details. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashSet; + /// use std::hash::RandomState; + /// + /// let s = RandomState::new(); + /// let mut set = HashSet::with_capacity_and_hasher(10, s); + /// set.insert(1); + /// ``` + #[inline] + #[stable(feature = "hashmap_build_hasher", since = "1.7.0")] + pub fn with_capacity_and_hasher(capacity: usize, hasher: S) -> HashSet { + HashSet { base: base::HashSet::with_capacity_and_hasher(capacity, hasher) } + } +} + +impl HashSet { + /// Creates a new empty hash set which will use the given hasher to hash + /// keys and will allocate memory using the provided allocator. + /// + /// The hash set is also created with the default initial capacity. + /// + /// Warning: `hasher` is normally randomly generated, and + /// is designed to allow `HashSet`s to be resistant to attacks that + /// cause many collisions and very poor performance. Setting it + /// manually using this function can expose a DoS attack vector. + /// + /// The `hash_builder` passed should implement the [`BuildHasher`] trait for + /// the `HashSet` to be useful, see its documentation for details. + #[inline] + #[unstable(feature = "allocator_api", issue = "32838")] + pub fn with_hasher_in(hasher: S, alloc: A) -> HashSet { + HashSet { base: base::HashSet::with_hasher_in(hasher, alloc) } + } + + /// Creates an empty `HashSet` with at least the specified capacity, using + /// `hasher` to hash the keys and `alloc` to allocate memory. + /// + /// The hash set will be able to hold at least `capacity` elements without + /// reallocating. This method is allowed to allocate for more elements than + /// `capacity`. If `capacity` is zero, the hash set will not allocate. + /// + /// Warning: `hasher` is normally randomly generated, and + /// is designed to allow `HashSet`s to be resistant to attacks that + /// cause many collisions and very poor performance. Setting it + /// manually using this function can expose a DoS attack vector. + /// + /// The `hash_builder` passed should implement the [`BuildHasher`] trait for + /// the `HashSet` to be useful, see its documentation for details. + #[inline] + #[unstable(feature = "allocator_api", issue = "32838")] + pub fn with_capacity_and_hasher_in(capacity: usize, hasher: S, alloc: A) -> HashSet { + HashSet { base: base::HashSet::with_capacity_and_hasher_in(capacity, hasher, alloc) } + } + + /// Returns the number of elements the set can hold without reallocating. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashSet; + /// let set: HashSet = HashSet::with_capacity(100); + /// assert!(set.capacity() >= 100); + /// ``` + #[inline] + #[stable(feature = "rust1", since = "1.0.0")] + pub fn capacity(&self) -> usize { + self.base.capacity() + } + + /// An iterator visiting all elements in arbitrary order. + /// The iterator element type is `&'a T`. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashSet; + /// let mut set = HashSet::new(); + /// set.insert("a"); + /// set.insert("b"); + /// + /// // Will print in an arbitrary order. + /// for x in set.iter() { + /// println!("{x}"); + /// } + /// ``` + /// + /// # Performance + /// + /// In the current implementation, iterating over set takes O(capacity) time + /// instead of O(len) because it internally visits empty buckets too. + #[inline] + #[rustc_lint_query_instability] + #[stable(feature = "rust1", since = "1.0.0")] + #[cfg_attr(not(test), rustc_diagnostic_item = "hashset_iter")] + pub fn iter(&self) -> Iter<'_, T> { + Iter { base: self.base.iter() } + } + + /// Returns the number of elements in the set. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashSet; + /// + /// let mut v = HashSet::new(); + /// assert_eq!(v.len(), 0); + /// v.insert(1); + /// assert_eq!(v.len(), 1); + /// ``` + #[inline] + #[stable(feature = "rust1", since = "1.0.0")] + pub fn len(&self) -> usize { + self.base.len() + } + + /// Returns `true` if the set contains no elements. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashSet; + /// + /// let mut v = HashSet::new(); + /// assert!(v.is_empty()); + /// v.insert(1); + /// assert!(!v.is_empty()); + /// ``` + #[inline] + #[stable(feature = "rust1", since = "1.0.0")] + pub fn is_empty(&self) -> bool { + self.base.is_empty() + } + + /// Clears the set, returning all elements as an iterator. Keeps the + /// allocated memory for reuse. + /// + /// If the returned iterator is dropped before being fully consumed, it + /// drops the remaining elements. The returned iterator keeps a mutable + /// borrow on the set to optimize its implementation. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashSet; + /// + /// let mut set = HashSet::from([1, 2, 3]); + /// assert!(!set.is_empty()); + /// + /// // print 1, 2, 3 in an arbitrary order + /// for i in set.drain() { + /// println!("{i}"); + /// } + /// + /// assert!(set.is_empty()); + /// ``` + #[inline] + #[rustc_lint_query_instability] + #[stable(feature = "drain", since = "1.6.0")] + pub fn drain(&mut self) -> Drain<'_, T, A> { + Drain { base: self.base.drain() } + } + + /// Creates an iterator which uses a closure to determine if an element should be removed. + /// + /// If the closure returns `true`, the element is removed from the set and + /// yielded. If the closure returns `false`, or panics, the element remains + /// in the set and will not be yielded. + /// + /// 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. + /// + /// [`retain`]: HashSet::retain + /// + /// # Examples + /// + /// Splitting a set into even and odd values, reusing the original set: + /// + /// ``` + /// use std::collections::HashSet; + /// + /// let mut set: HashSet = (0..8).collect(); + /// let extracted: HashSet = set.extract_if(|v| v % 2 == 0).collect(); + /// + /// let mut evens = extracted.into_iter().collect::>(); + /// let mut odds = set.into_iter().collect::>(); + /// evens.sort(); + /// odds.sort(); + /// + /// assert_eq!(evens, vec![0, 2, 4, 6]); + /// assert_eq!(odds, vec![1, 3, 5, 7]); + /// ``` + #[inline] + #[rustc_lint_query_instability] + #[stable(feature = "hash_extract_if", since = "1.88.0")] + pub fn extract_if(&mut self, pred: F) -> ExtractIf<'_, T, F, A> + where + F: FnMut(&T) -> bool, + { + ExtractIf { base: self.base.extract_if(pred) } + } + + /// Retains only the elements specified by the predicate. + /// + /// In other words, remove all elements `e` for which `f(&e)` returns `false`. + /// The elements are visited in unsorted (and unspecified) order. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashSet; + /// + /// let mut set = HashSet::from([1, 2, 3, 4, 5, 6]); + /// set.retain(|&k| k % 2 == 0); + /// assert_eq!(set, HashSet::from([2, 4, 6])); + /// ``` + /// + /// # Performance + /// + /// In the current implementation, this operation takes O(capacity) time + /// instead of O(len) because it internally visits empty buckets too. + #[rustc_lint_query_instability] + #[stable(feature = "retain_hash_collection", since = "1.18.0")] + pub fn retain(&mut self, f: F) + where + F: FnMut(&T) -> bool, + { + self.base.retain(f) + } + + /// Clears the set, removing all values. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashSet; + /// + /// let mut v = HashSet::new(); + /// v.insert(1); + /// v.clear(); + /// assert!(v.is_empty()); + /// ``` + #[inline] + #[stable(feature = "rust1", since = "1.0.0")] + pub fn clear(&mut self) { + self.base.clear() + } + + /// Returns a reference to the set's [`BuildHasher`]. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashSet; + /// use std::hash::RandomState; + /// + /// let hasher = RandomState::new(); + /// let set: HashSet = HashSet::with_hasher(hasher); + /// let hasher: &RandomState = set.hasher(); + /// ``` + #[inline] + #[stable(feature = "hashmap_public_hasher", since = "1.9.0")] + pub fn hasher(&self) -> &S { + self.base.hasher() + } +} + +impl HashSet +where + T: Eq + Hash, + S: BuildHasher, + A: Allocator, +{ + /// Reserves capacity for at least `additional` more elements to be inserted + /// in the `HashSet`. The collection may reserve more space to speculatively + /// avoid frequent reallocations. After calling `reserve`, + /// capacity will be greater than or equal to `self.len() + additional`. + /// Does nothing if capacity is already sufficient. + /// + /// # Panics + /// + /// Panics if the new allocation size overflows `usize`. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashSet; + /// let mut set: HashSet = HashSet::new(); + /// set.reserve(10); + /// assert!(set.capacity() >= 10); + /// ``` + #[inline] + #[stable(feature = "rust1", since = "1.0.0")] + pub fn reserve(&mut self, additional: usize) { + self.base.reserve(additional) + } + + /// Tries to reserve capacity for at least `additional` more elements to be inserted + /// in the `HashSet`. The collection may reserve more space to speculatively + /// avoid frequent reallocations. After calling `try_reserve`, + /// capacity will be greater than or equal to `self.len() + additional` if + /// it returns `Ok(())`. + /// Does nothing if capacity is already sufficient. + /// + /// # Errors + /// + /// If the capacity overflows, or the allocator reports a failure, then an error + /// is returned. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashSet; + /// let mut set: HashSet = HashSet::new(); + /// set.try_reserve(10).expect("why is the test harness OOMing on a handful of bytes?"); + /// ``` + #[inline] + #[stable(feature = "try_reserve", since = "1.57.0")] + pub fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError> { + self.base.try_reserve(additional).map_err(map_try_reserve_error) + } + + /// Shrinks the capacity of the set as much as possible. It will drop + /// down as much as possible while maintaining the internal rules + /// and possibly leaving some space in accordance with the resize policy. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashSet; + /// + /// let mut set = HashSet::with_capacity(100); + /// set.insert(1); + /// set.insert(2); + /// assert!(set.capacity() >= 100); + /// set.shrink_to_fit(); + /// assert!(set.capacity() >= 2); + /// ``` + #[inline] + #[stable(feature = "rust1", since = "1.0.0")] + pub fn shrink_to_fit(&mut self) { + self.base.shrink_to_fit() + } + + /// Shrinks the capacity of the set with a lower limit. It will drop + /// down no lower than the supplied limit while maintaining the internal rules + /// and possibly leaving some space in accordance with the resize policy. + /// + /// If the current capacity is less than the lower limit, this is a no-op. + /// # Examples + /// + /// ``` + /// use std::collections::HashSet; + /// + /// let mut set = HashSet::with_capacity(100); + /// set.insert(1); + /// set.insert(2); + /// assert!(set.capacity() >= 100); + /// set.shrink_to(10); + /// assert!(set.capacity() >= 10); + /// set.shrink_to(0); + /// assert!(set.capacity() >= 2); + /// ``` + #[inline] + #[stable(feature = "shrink_to", since = "1.56.0")] + pub fn shrink_to(&mut self, min_capacity: usize) { + self.base.shrink_to(min_capacity) + } + + /// Visits the values representing the difference, + /// i.e., the values that are in `self` but not in `other`. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashSet; + /// let a = HashSet::from([1, 2, 3]); + /// let b = HashSet::from([4, 2, 3, 4]); + /// + /// // Can be seen as `a - b`. + /// for x in a.difference(&b) { + /// println!("{x}"); // Print 1 + /// } + /// + /// let diff: HashSet<_> = a.difference(&b).collect(); + /// assert_eq!(diff, [1].iter().collect()); + /// + /// // Note that difference is not symmetric, + /// // and `b - a` means something else: + /// let diff: HashSet<_> = b.difference(&a).collect(); + /// assert_eq!(diff, [4].iter().collect()); + /// ``` + #[inline] + #[rustc_lint_query_instability] + #[stable(feature = "rust1", since = "1.0.0")] + pub fn difference<'a>(&'a self, other: &'a HashSet) -> Difference<'a, T, S, A> { + Difference { iter: self.iter(), other } + } + + /// Visits the values representing the symmetric difference, + /// i.e., the values that are in `self` or in `other` but not in both. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashSet; + /// let a = HashSet::from([1, 2, 3]); + /// let b = HashSet::from([4, 2, 3, 4]); + /// + /// // Print 1, 4 in arbitrary order. + /// for x in a.symmetric_difference(&b) { + /// println!("{x}"); + /// } + /// + /// let diff1: HashSet<_> = a.symmetric_difference(&b).collect(); + /// let diff2: HashSet<_> = b.symmetric_difference(&a).collect(); + /// + /// assert_eq!(diff1, diff2); + /// assert_eq!(diff1, [1, 4].iter().collect()); + /// ``` + #[inline] + #[rustc_lint_query_instability] + #[stable(feature = "rust1", since = "1.0.0")] + pub fn symmetric_difference<'a>( + &'a self, + other: &'a HashSet, + ) -> SymmetricDifference<'a, T, S, A> { + SymmetricDifference { iter: self.difference(other).chain(other.difference(self)) } + } + + /// Visits the values representing the intersection, + /// i.e., the values that are both in `self` and `other`. + /// + /// When an equal element is present in `self` and `other` + /// then the resulting `Intersection` may yield references to + /// one or the other. This can be relevant if `T` contains fields which + /// are not compared by its `Eq` implementation, and may hold different + /// value between the two equal copies of `T` in the two sets. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashSet; + /// let a = HashSet::from([1, 2, 3]); + /// let b = HashSet::from([4, 2, 3, 4]); + /// + /// // Print 2, 3 in arbitrary order. + /// for x in a.intersection(&b) { + /// println!("{x}"); + /// } + /// + /// let intersection: HashSet<_> = a.intersection(&b).collect(); + /// assert_eq!(intersection, [2, 3].iter().collect()); + /// ``` + #[inline] + #[rustc_lint_query_instability] + #[stable(feature = "rust1", since = "1.0.0")] + pub fn intersection<'a>(&'a self, other: &'a HashSet) -> Intersection<'a, T, S, A> { + if self.len() <= other.len() { + Intersection { iter: self.iter(), other } + } else { + Intersection { iter: other.iter(), other: self } + } + } + + /// Visits the values representing the union, + /// i.e., all the values in `self` or `other`, without duplicates. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashSet; + /// let a = HashSet::from([1, 2, 3]); + /// let b = HashSet::from([4, 2, 3, 4]); + /// + /// // Print 1, 2, 3, 4 in arbitrary order. + /// for x in a.union(&b) { + /// println!("{x}"); + /// } + /// + /// let union: HashSet<_> = a.union(&b).collect(); + /// assert_eq!(union, [1, 2, 3, 4].iter().collect()); + /// ``` + #[inline] + #[rustc_lint_query_instability] + #[stable(feature = "rust1", since = "1.0.0")] + pub fn union<'a>(&'a self, other: &'a HashSet) -> Union<'a, T, S, A> { + if self.len() >= other.len() { + Union { iter: self.iter().chain(other.difference(self)) } + } else { + Union { iter: other.iter().chain(self.difference(other)) } + } + } + + /// Returns `true` if the set contains a value. + /// + /// The value may be any borrowed form of the set's value type, but + /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for + /// the value type. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashSet; + /// + /// let set = HashSet::from([1, 2, 3]); + /// assert_eq!(set.contains(&1), true); + /// assert_eq!(set.contains(&4), false); + /// ``` + #[inline] + #[stable(feature = "rust1", since = "1.0.0")] + pub fn contains(&self, value: &Q) -> bool + where + T: Borrow, + Q: Hash + Eq, + { + self.base.contains(value) + } + + /// Returns a reference to the value in the set, if any, that is equal to the given value. + /// + /// The value may be any borrowed form of the set's value type, but + /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for + /// the value type. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashSet; + /// + /// let set = HashSet::from([1, 2, 3]); + /// assert_eq!(set.get(&2), Some(&2)); + /// assert_eq!(set.get(&4), None); + /// ``` + #[inline] + #[stable(feature = "set_recovery", since = "1.9.0")] + pub fn get(&self, value: &Q) -> Option<&T> + where + T: Borrow, + Q: Hash + Eq, + { + self.base.get(value) + } + + /// Inserts the given `value` into the set if it is not present, then + /// returns a reference to the value in the set. + /// + /// # Examples + /// + /// ``` + /// #![feature(hash_set_entry)] + /// + /// use std::collections::HashSet; + /// + /// let mut set = HashSet::from([1, 2, 3]); + /// assert_eq!(set.len(), 3); + /// assert_eq!(set.get_or_insert(2), &2); + /// assert_eq!(set.get_or_insert(100), &100); + /// assert_eq!(set.len(), 4); // 100 was inserted + /// ``` + #[inline] + #[unstable(feature = "hash_set_entry", issue = "60896")] + pub fn get_or_insert(&mut self, value: T) -> &T { + // Although the raw entry gives us `&mut T`, we only return `&T` to be consistent with + // `get`. Key mutation is "raw" because you're not supposed to affect `Eq` or `Hash`. + self.base.get_or_insert(value) + } + + /// Inserts a value computed from `f` into the set if the given `value` is + /// not present, then returns a reference to the value in the set. + /// + /// # Examples + /// + /// ``` + /// #![feature(hash_set_entry)] + /// + /// use std::collections::HashSet; + /// + /// let mut set: HashSet = ["cat", "dog", "horse"] + /// .iter().map(|&pet| pet.to_owned()).collect(); + /// + /// assert_eq!(set.len(), 3); + /// for &pet in &["cat", "dog", "fish"] { + /// let value = set.get_or_insert_with(pet, str::to_owned); + /// assert_eq!(value, pet); + /// } + /// assert_eq!(set.len(), 4); // a new "fish" was inserted + /// ``` + #[inline] + #[unstable(feature = "hash_set_entry", issue = "60896")] + pub fn get_or_insert_with(&mut self, value: &Q, f: F) -> &T + where + T: Borrow, + Q: Hash + Eq, + F: FnOnce(&Q) -> T, + { + // Although the raw entry gives us `&mut T`, we only return `&T` to be consistent with + // `get`. Key mutation is "raw" because you're not supposed to affect `Eq` or `Hash`. + self.base.get_or_insert_with(value, f) + } + + /// Gets the given value's corresponding entry in the set for in-place manipulation. + /// + /// # Examples + /// + /// ``` + /// #![feature(hash_set_entry)] + /// + /// use std::collections::HashSet; + /// use std::collections::hash_set::Entry::*; + /// + /// let mut singles = HashSet::new(); + /// let mut dupes = HashSet::new(); + /// + /// for ch in "a short treatise on fungi".chars() { + /// if let Vacant(dupe_entry) = dupes.entry(ch) { + /// // We haven't already seen a duplicate, so + /// // check if we've at least seen it once. + /// match singles.entry(ch) { + /// Vacant(single_entry) => { + /// // We found a new character for the first time. + /// single_entry.insert() + /// } + /// Occupied(single_entry) => { + /// // We've already seen this once, "move" it to dupes. + /// single_entry.remove(); + /// dupe_entry.insert(); + /// } + /// } + /// } + /// } + /// + /// assert!(!singles.contains(&'t') && dupes.contains(&'t')); + /// assert!(singles.contains(&'u') && !dupes.contains(&'u')); + /// assert!(!singles.contains(&'v') && !dupes.contains(&'v')); + /// ``` + #[inline] + #[unstable(feature = "hash_set_entry", issue = "60896")] + pub fn entry(&mut self, value: T) -> Entry<'_, T, S, A> { + map_entry(self.base.entry(value)) + } + + /// Returns `true` if `self` has no elements in common with `other`. + /// This is equivalent to checking for an empty intersection. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashSet; + /// + /// let a = HashSet::from([1, 2, 3]); + /// let mut b = HashSet::new(); + /// + /// assert_eq!(a.is_disjoint(&b), true); + /// b.insert(4); + /// assert_eq!(a.is_disjoint(&b), true); + /// b.insert(1); + /// assert_eq!(a.is_disjoint(&b), false); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn is_disjoint(&self, other: &HashSet) -> bool { + if self.len() <= other.len() { + self.iter().all(|v| !other.contains(v)) + } else { + other.iter().all(|v| !self.contains(v)) + } + } + + /// Returns `true` if the set is a subset of another, + /// i.e., `other` contains at least all the values in `self`. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashSet; + /// + /// let sup = HashSet::from([1, 2, 3]); + /// let mut set = HashSet::new(); + /// + /// assert_eq!(set.is_subset(&sup), true); + /// set.insert(2); + /// assert_eq!(set.is_subset(&sup), true); + /// set.insert(4); + /// assert_eq!(set.is_subset(&sup), false); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn is_subset(&self, other: &HashSet) -> bool { + if self.len() <= other.len() { self.iter().all(|v| other.contains(v)) } else { false } + } + + /// Returns `true` if the set is a superset of another, + /// i.e., `self` contains at least all the values in `other`. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashSet; + /// + /// let sub = HashSet::from([1, 2]); + /// let mut set = HashSet::new(); + /// + /// assert_eq!(set.is_superset(&sub), false); + /// + /// set.insert(0); + /// set.insert(1); + /// assert_eq!(set.is_superset(&sub), false); + /// + /// set.insert(2); + /// assert_eq!(set.is_superset(&sub), true); + /// ``` + #[inline] + #[stable(feature = "rust1", since = "1.0.0")] + pub fn is_superset(&self, other: &HashSet) -> bool { + other.is_subset(self) + } + + /// Adds a value to the set. + /// + /// 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, + /// and the set is not modified: original value is not replaced, + /// and the value passed as argument is dropped. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashSet; + /// + /// let mut set = HashSet::new(); + /// + /// assert_eq!(set.insert(2), true); + /// assert_eq!(set.insert(2), false); + /// assert_eq!(set.len(), 1); + /// ``` + #[inline] + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_confusables("push", "append", "put")] + pub fn insert(&mut self, value: T) -> bool { + self.base.insert(value) + } + + /// Adds a value to the set, replacing the existing value, if any, that is equal to the given + /// one. Returns the replaced value. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashSet; + /// + /// let mut set = HashSet::new(); + /// set.insert(Vec::::new()); + /// + /// assert_eq!(set.get(&[][..]).unwrap().capacity(), 0); + /// set.replace(Vec::with_capacity(10)); + /// assert_eq!(set.get(&[][..]).unwrap().capacity(), 10); + /// ``` + #[inline] + #[stable(feature = "set_recovery", since = "1.9.0")] + #[rustc_confusables("swap")] + pub fn replace(&mut self, value: T) -> Option { + self.base.replace(value) + } + + /// Removes a value from the set. Returns whether the value was + /// present in the set. + /// + /// The value may be any borrowed form of the set's value type, but + /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for + /// the value type. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashSet; + /// + /// let mut set = HashSet::new(); + /// + /// set.insert(2); + /// assert_eq!(set.remove(&2), true); + /// assert_eq!(set.remove(&2), false); + /// ``` + #[inline] + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_confusables("delete", "take")] + pub fn remove(&mut self, value: &Q) -> bool + where + T: Borrow, + Q: Hash + Eq, + { + self.base.remove(value) + } + + /// Removes and returns the value in the set, if any, that is equal to the given one. + /// + /// The value may be any borrowed form of the set's value type, but + /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for + /// the value type. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashSet; + /// + /// let mut set = HashSet::from([1, 2, 3]); + /// assert_eq!(set.take(&2), Some(2)); + /// assert_eq!(set.take(&2), None); + /// ``` + #[inline] + #[stable(feature = "set_recovery", since = "1.9.0")] + pub fn take(&mut self, value: &Q) -> Option + where + T: Borrow, + Q: Hash + Eq, + { + self.base.take(value) + } +} + +#[inline] +fn map_entry<'a, K: 'a, V: 'a, A: Allocator>(raw: base::Entry<'a, K, V, A>) -> Entry<'a, K, V, A> { + match raw { + base::Entry::Occupied(base) => Entry::Occupied(OccupiedEntry { base }), + base::Entry::Vacant(base) => Entry::Vacant(VacantEntry { base }), + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Clone for HashSet +where + T: Clone, + S: Clone, + A: Allocator + Clone, +{ + #[inline] + fn clone(&self) -> Self { + Self { base: self.base.clone() } + } + + /// Overwrites the contents of `self` with a clone of the contents of `source`. + /// + /// This method is preferred over simply assigning `source.clone()` to `self`, + /// as it avoids reallocation if possible. + #[inline] + fn clone_from(&mut self, other: &Self) { + self.base.clone_from(&other.base); + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl PartialEq for HashSet +where + T: Eq + Hash, + S: BuildHasher, + A: Allocator, +{ + fn eq(&self, other: &HashSet) -> bool { + if self.len() != other.len() { + return false; + } + + self.iter().all(|key| other.contains(key)) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Eq for HashSet +where + T: Eq + Hash, + S: BuildHasher, + A: Allocator, +{ +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl fmt::Debug for HashSet +where + T: fmt::Debug, + A: Allocator, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_set().entries(self.iter()).finish() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl FromIterator for HashSet +where + T: Eq + Hash, + S: BuildHasher + Default, +{ + #[inline] + fn from_iter>(iter: I) -> HashSet { + let mut set = HashSet::with_hasher(Default::default()); + set.extend(iter); + set + } +} + +#[stable(feature = "std_collections_from_array", since = "1.56.0")] +// Note: as what is currently the most convenient built-in way to construct +// a HashSet, a simple usage of this function must not *require* the user +// to provide a type annotation in order to infer the third type parameter +// (the hasher parameter, conventionally "S"). +// To that end, this impl is defined using RandomState as the concrete +// type of S, rather than being generic over `S: BuildHasher + Default`. +// It is expected that users who want to specify a hasher will manually use +// `with_capacity_and_hasher`. +// If type parameter defaults worked on impls, and if type parameter +// defaults could be mixed with const generics, then perhaps +// this could be generalized. +// See also the equivalent impl on HashMap. +impl From<[T; N]> for HashSet +where + T: Eq + Hash, +{ + /// Converts a `[T; N]` into a `HashSet`. + /// + /// If the array contains any equal values, + /// all but one will be dropped. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashSet; + /// + /// let set1 = HashSet::from([1, 2, 3, 4]); + /// let set2: HashSet<_> = [1, 2, 3, 4].into(); + /// assert_eq!(set1, set2); + /// ``` + fn from(arr: [T; N]) -> Self { + Self::from_iter(arr) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Extend for HashSet +where + T: Eq + Hash, + S: BuildHasher, + A: Allocator, +{ + #[inline] + fn extend>(&mut self, iter: I) { + self.base.extend(iter); + } + + #[inline] + fn extend_one(&mut self, item: T) { + self.base.insert(item); + } + + #[inline] + fn extend_reserve(&mut self, additional: usize) { + self.base.extend_reserve(additional); + } +} + +#[stable(feature = "hash_extend_copy", since = "1.4.0")] +impl<'a, T, S, A> Extend<&'a T> for HashSet +where + T: 'a + Eq + Hash + Copy, + S: BuildHasher, + A: Allocator, +{ + #[inline] + fn extend>(&mut self, iter: I) { + self.extend(iter.into_iter().cloned()); + } + + #[inline] + fn extend_one(&mut self, &item: &'a T) { + self.base.insert(item); + } + + #[inline] + fn extend_reserve(&mut self, additional: usize) { + Extend::::extend_reserve(self, additional) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +#[rustc_const_unstable(feature = "const_default", issue = "143894")] +impl const Default for HashSet +where + S: [const] Default, +{ + /// Creates an empty `HashSet` with the `Default` value for the hasher. + #[inline] + fn default() -> HashSet { + HashSet { base: base::HashSet::with_hasher(Default::default()) } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl BitOr<&HashSet> for &HashSet +where + T: Eq + Hash + Clone, + S: BuildHasher + Default, +{ + type Output = HashSet; + + /// Returns the union of `self` and `rhs` as a new `HashSet`. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashSet; + /// + /// let a = HashSet::from([1, 2, 3]); + /// let b = HashSet::from([3, 4, 5]); + /// + /// let set = &a | &b; + /// + /// let mut i = 0; + /// let expected = [1, 2, 3, 4, 5]; + /// for x in &set { + /// assert!(expected.contains(x)); + /// i += 1; + /// } + /// assert_eq!(i, expected.len()); + /// ``` + fn bitor(self, rhs: &HashSet) -> HashSet { + self.union(rhs).cloned().collect() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl BitAnd<&HashSet> for &HashSet +where + T: Eq + Hash + Clone, + S: BuildHasher + Default, +{ + type Output = HashSet; + + /// Returns the intersection of `self` and `rhs` as a new `HashSet`. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashSet; + /// + /// let a = HashSet::from([1, 2, 3]); + /// let b = HashSet::from([2, 3, 4]); + /// + /// let set = &a & &b; + /// + /// let mut i = 0; + /// let expected = [2, 3]; + /// for x in &set { + /// assert!(expected.contains(x)); + /// i += 1; + /// } + /// assert_eq!(i, expected.len()); + /// ``` + fn bitand(self, rhs: &HashSet) -> HashSet { + self.intersection(rhs).cloned().collect() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl BitXor<&HashSet> for &HashSet +where + T: Eq + Hash + Clone, + S: BuildHasher + Default, +{ + type Output = HashSet; + + /// Returns the symmetric difference of `self` and `rhs` as a new `HashSet`. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashSet; + /// + /// let a = HashSet::from([1, 2, 3]); + /// let b = HashSet::from([3, 4, 5]); + /// + /// let set = &a ^ &b; + /// + /// let mut i = 0; + /// let expected = [1, 2, 4, 5]; + /// for x in &set { + /// assert!(expected.contains(x)); + /// i += 1; + /// } + /// assert_eq!(i, expected.len()); + /// ``` + fn bitxor(self, rhs: &HashSet) -> HashSet { + self.symmetric_difference(rhs).cloned().collect() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Sub<&HashSet> for &HashSet +where + T: Eq + Hash + Clone, + S: BuildHasher + Default, +{ + type Output = HashSet; + + /// Returns the difference of `self` and `rhs` as a new `HashSet`. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashSet; + /// + /// let a = HashSet::from([1, 2, 3]); + /// let b = HashSet::from([3, 4, 5]); + /// + /// let set = &a - &b; + /// + /// let mut i = 0; + /// let expected = [1, 2]; + /// for x in &set { + /// assert!(expected.contains(x)); + /// i += 1; + /// } + /// assert_eq!(i, expected.len()); + /// ``` + fn sub(self, rhs: &HashSet) -> HashSet { + self.difference(rhs).cloned().collect() + } +} + +/// An iterator over the items of a `HashSet`. +/// +/// This `struct` is created by the [`iter`] method on [`HashSet`]. +/// See its documentation for more. +/// +/// [`iter`]: HashSet::iter +/// +/// # Examples +/// +/// ``` +/// use std::collections::HashSet; +/// +/// let a = HashSet::from([1, 2, 3]); +/// +/// let mut iter = a.iter(); +/// ``` +#[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr(not(test), rustc_diagnostic_item = "hashset_iter_ty")] +pub struct Iter<'a, K: 'a> { + base: base::Iter<'a, K>, +} + +#[stable(feature = "default_iters_hash", since = "1.83.0")] +impl Default for Iter<'_, K> { + #[inline] + fn default() -> Self { + Iter { base: Default::default() } + } +} + +/// An owning iterator over the items of a `HashSet`. +/// +/// This `struct` is created by the [`into_iter`] method on [`HashSet`] +/// (provided by the [`IntoIterator`] trait). See its documentation for more. +/// +/// [`into_iter`]: IntoIterator::into_iter +/// +/// # Examples +/// +/// ``` +/// use std::collections::HashSet; +/// +/// let a = HashSet::from([1, 2, 3]); +/// +/// let mut iter = a.into_iter(); +/// ``` +#[stable(feature = "rust1", since = "1.0.0")] +pub struct IntoIter< + K, + #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, +> { + base: base::IntoIter, +} + +#[stable(feature = "default_iters_hash", since = "1.83.0")] +impl Default for IntoIter { + #[inline] + fn default() -> Self { + IntoIter { base: Default::default() } + } +} + +/// A draining iterator over the items of a `HashSet`. +/// +/// This `struct` is created by the [`drain`] method on [`HashSet`]. +/// See its documentation for more. +/// +/// [`drain`]: HashSet::drain +/// +/// # Examples +/// +/// ``` +/// use std::collections::HashSet; +/// +/// let mut a = HashSet::from([1, 2, 3]); +/// +/// let mut drain = a.drain(); +/// ``` +#[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr(not(test), rustc_diagnostic_item = "hashset_drain_ty")] +pub struct Drain< + 'a, + K: 'a, + #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, +> { + base: base::Drain<'a, K, A>, +} + +/// A draining, filtering iterator over the items of a `HashSet`. +/// +/// This `struct` is created by the [`extract_if`] method on [`HashSet`]. +/// +/// [`extract_if`]: HashSet::extract_if +/// +/// # Examples +/// +/// ``` +/// use std::collections::HashSet; +/// +/// let mut a = HashSet::from([1, 2, 3]); +/// +/// let mut extract_ifed = a.extract_if(|v| v % 2 == 0); +/// ``` +#[stable(feature = "hash_extract_if", since = "1.88.0")] +#[must_use = "iterators are lazy and do nothing unless consumed; \ + use `retain` to remove and discard elements"] +pub struct ExtractIf< + 'a, + K, + F, + #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, +> { + base: base::ExtractIf<'a, K, F, A>, +} + +/// A lazy iterator producing elements in the intersection of `HashSet`s. +/// +/// This `struct` is created by the [`intersection`] method on [`HashSet`]. +/// See its documentation for more. +/// +/// [`intersection`]: HashSet::intersection +/// +/// # Examples +/// +/// ``` +/// use std::collections::HashSet; +/// +/// let a = HashSet::from([1, 2, 3]); +/// let b = HashSet::from([4, 2, 3, 4]); +/// +/// let mut intersection = a.intersection(&b); +/// ``` +#[must_use = "this returns the intersection as an iterator, \ + without modifying either input set"] +#[stable(feature = "rust1", since = "1.0.0")] +pub struct Intersection< + 'a, + T: 'a, + S: 'a, + #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, +> { + // iterator of the first set + iter: Iter<'a, T>, + // the second set + other: &'a HashSet, +} + +/// A lazy iterator producing elements in the difference of `HashSet`s. +/// +/// This `struct` is created by the [`difference`] method on [`HashSet`]. +/// See its documentation for more. +/// +/// [`difference`]: HashSet::difference +/// +/// # Examples +/// +/// ``` +/// use std::collections::HashSet; +/// +/// let a = HashSet::from([1, 2, 3]); +/// let b = HashSet::from([4, 2, 3, 4]); +/// +/// let mut difference = a.difference(&b); +/// ``` +#[must_use = "this returns the difference as an iterator, \ + without modifying either input set"] +#[stable(feature = "rust1", since = "1.0.0")] +pub struct Difference< + 'a, + T: 'a, + S: 'a, + #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, +> { + // iterator of the first set + iter: Iter<'a, T>, + // the second set + other: &'a HashSet, +} + +/// A lazy iterator producing elements in the symmetric difference of `HashSet`s. +/// +/// This `struct` is created by the [`symmetric_difference`] method on +/// [`HashSet`]. See its documentation for more. +/// +/// [`symmetric_difference`]: HashSet::symmetric_difference +/// +/// # Examples +/// +/// ``` +/// use std::collections::HashSet; +/// +/// let a = HashSet::from([1, 2, 3]); +/// let b = HashSet::from([4, 2, 3, 4]); +/// +/// let mut intersection = a.symmetric_difference(&b); +/// ``` +#[must_use = "this returns the difference as an iterator, \ + without modifying either input set"] +#[stable(feature = "rust1", since = "1.0.0")] +pub struct SymmetricDifference< + 'a, + T: 'a, + S: 'a, + #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, +> { + iter: Chain, Difference<'a, T, S, A>>, +} + +/// A lazy iterator producing elements in the union of `HashSet`s. +/// +/// This `struct` is created by the [`union`] method on [`HashSet`]. +/// See its documentation for more. +/// +/// [`union`]: HashSet::union +/// +/// # Examples +/// +/// ``` +/// use std::collections::HashSet; +/// +/// let a = HashSet::from([1, 2, 3]); +/// let b = HashSet::from([4, 2, 3, 4]); +/// +/// let mut union_iter = a.union(&b); +/// ``` +#[must_use = "this returns the union as an iterator, \ + without modifying either input set"] +#[stable(feature = "rust1", since = "1.0.0")] +pub struct Union< + 'a, + T: 'a, + S: 'a, + #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, +> { + iter: Chain, Difference<'a, T, S, A>>, +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, T, S, A: Allocator> IntoIterator for &'a HashSet { + type Item = &'a T; + type IntoIter = Iter<'a, T>; + + #[inline] + #[rustc_lint_query_instability] + fn into_iter(self) -> Iter<'a, T> { + self.iter() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl IntoIterator for HashSet { + type Item = T; + type IntoIter = IntoIter; + + /// Creates a consuming iterator, that is, one that moves each value out + /// of the set in arbitrary order. The set cannot be used after calling + /// this. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashSet; + /// let mut set = HashSet::new(); + /// set.insert("a".to_string()); + /// set.insert("b".to_string()); + /// + /// // Not possible to collect to a Vec with a regular `.iter()`. + /// let v: Vec = set.into_iter().collect(); + /// + /// // Will print in an arbitrary order. + /// for x in &v { + /// println!("{x}"); + /// } + /// ``` + #[inline] + #[rustc_lint_query_instability] + fn into_iter(self) -> IntoIter { + IntoIter { base: self.base.into_iter() } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Clone for Iter<'_, K> { + #[inline] + fn clone(&self) -> Self { + Iter { base: self.base.clone() } + } +} +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, K> Iterator for Iter<'a, K> { + type Item = &'a K; + + #[inline] + fn next(&mut self) -> Option<&'a K> { + self.base.next() + } + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.base.size_hint() + } + #[inline] + fn count(self) -> usize { + self.base.len() + } + #[inline] + fn fold(self, init: B, f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.base.fold(init, f) + } +} +#[stable(feature = "rust1", since = "1.0.0")] +impl ExactSizeIterator for Iter<'_, K> { + #[inline] + fn len(&self) -> usize { + self.base.len() + } +} +#[stable(feature = "fused", since = "1.26.0")] +impl FusedIterator for Iter<'_, K> {} + +#[stable(feature = "std_debug", since = "1.16.0")] +impl fmt::Debug for Iter<'_, K> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.clone()).finish() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Iterator for IntoIter { + type Item = K; + + #[inline] + fn next(&mut self) -> Option { + self.base.next() + } + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.base.size_hint() + } + #[inline] + fn count(self) -> usize { + self.base.len() + } + #[inline] + fn fold(self, init: B, f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.base.fold(init, f) + } +} +#[stable(feature = "rust1", since = "1.0.0")] +impl ExactSizeIterator for IntoIter { + #[inline] + fn len(&self) -> usize { + self.base.len() + } +} +#[stable(feature = "fused", since = "1.26.0")] +impl FusedIterator for IntoIter {} + +#[stable(feature = "std_debug", since = "1.16.0")] +impl fmt::Debug for IntoIter { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Debug::fmt(&self.base, f) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, K, A: Allocator> Iterator for Drain<'a, K, A> { + type Item = K; + + #[inline] + fn next(&mut self) -> Option { + self.base.next() + } + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.base.size_hint() + } + #[inline] + fn fold(self, init: B, f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.base.fold(init, f) + } +} +#[stable(feature = "rust1", since = "1.0.0")] +impl ExactSizeIterator for Drain<'_, K, A> { + #[inline] + fn len(&self) -> usize { + self.base.len() + } +} +#[stable(feature = "fused", since = "1.26.0")] +impl FusedIterator for Drain<'_, K, A> {} + +#[stable(feature = "std_debug", since = "1.16.0")] +impl fmt::Debug for Drain<'_, K, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Debug::fmt(&self.base, f) + } +} + +#[stable(feature = "hash_extract_if", since = "1.88.0")] +impl Iterator for ExtractIf<'_, K, F, A> +where + F: FnMut(&K) -> bool, +{ + type Item = K; + + #[inline] + fn next(&mut self) -> Option { + self.base.next() + } + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.base.size_hint() + } +} + +#[stable(feature = "hash_extract_if", since = "1.88.0")] +impl FusedIterator for ExtractIf<'_, K, F, A> where F: FnMut(&K) -> bool {} + +#[stable(feature = "hash_extract_if", since = "1.88.0")] +impl fmt::Debug for ExtractIf<'_, K, F, A> +where + K: fmt::Debug, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("ExtractIf").finish_non_exhaustive() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Clone for Intersection<'_, T, S, A> { + #[inline] + fn clone(&self) -> Self { + Intersection { iter: self.iter.clone(), ..*self } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, T, S, A> Iterator for Intersection<'a, T, S, A> +where + T: Eq + Hash, + S: BuildHasher, + A: Allocator, +{ + type Item = &'a T; + + #[inline] + fn next(&mut self) -> Option<&'a T> { + loop { + let elt = self.iter.next()?; + if self.other.contains(elt) { + return Some(elt); + } + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + let (_, upper) = self.iter.size_hint(); + (0, upper) + } + + #[inline] + fn fold(self, init: B, mut f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.iter.fold(init, |acc, elt| if self.other.contains(elt) { f(acc, elt) } else { acc }) + } +} + +#[stable(feature = "std_debug", since = "1.16.0")] +impl fmt::Debug for Intersection<'_, T, S, A> +where + T: fmt::Debug + Eq + Hash, + S: BuildHasher, + A: Allocator, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.clone()).finish() + } +} + +#[stable(feature = "fused", since = "1.26.0")] +impl FusedIterator for Intersection<'_, T, S, A> +where + T: Eq + Hash, + S: BuildHasher, + A: Allocator, +{ +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Clone for Difference<'_, T, S, A> { + #[inline] + fn clone(&self) -> Self { + Difference { iter: self.iter.clone(), ..*self } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, T, S, A> Iterator for Difference<'a, T, S, A> +where + T: Eq + Hash, + S: BuildHasher, + A: Allocator, +{ + type Item = &'a T; + + #[inline] + fn next(&mut self) -> Option<&'a T> { + loop { + let elt = self.iter.next()?; + if !self.other.contains(elt) { + return Some(elt); + } + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + let (_, upper) = self.iter.size_hint(); + (0, upper) + } + + #[inline] + fn fold(self, init: B, mut f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.iter.fold(init, |acc, elt| if self.other.contains(elt) { acc } else { f(acc, elt) }) + } +} + +#[stable(feature = "fused", since = "1.26.0")] +impl FusedIterator for Difference<'_, T, S, A> +where + T: Eq + Hash, + S: BuildHasher, + A: Allocator, +{ +} + +#[stable(feature = "std_debug", since = "1.16.0")] +impl fmt::Debug for Difference<'_, T, S, A> +where + T: fmt::Debug + Eq + Hash, + S: BuildHasher, + A: Allocator, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.clone()).finish() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Clone for SymmetricDifference<'_, T, S, A> { + #[inline] + fn clone(&self) -> Self { + SymmetricDifference { iter: self.iter.clone() } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, T, S, A> Iterator for SymmetricDifference<'a, T, S, A> +where + T: Eq + Hash, + S: BuildHasher, + A: Allocator, +{ + type Item = &'a T; + + #[inline] + fn next(&mut self) -> Option<&'a T> { + self.iter.next() + } + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } + #[inline] + fn fold(self, init: B, f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.iter.fold(init, f) + } +} + +#[stable(feature = "fused", since = "1.26.0")] +impl FusedIterator for SymmetricDifference<'_, T, S, A> +where + T: Eq + Hash, + S: BuildHasher, + A: Allocator, +{ +} + +#[stable(feature = "std_debug", since = "1.16.0")] +impl fmt::Debug for SymmetricDifference<'_, T, S, A> +where + T: fmt::Debug + Eq + Hash, + S: BuildHasher, + A: Allocator, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.clone()).finish() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Clone for Union<'_, T, S, A> { + #[inline] + fn clone(&self) -> Self { + Union { iter: self.iter.clone() } + } +} + +#[stable(feature = "fused", since = "1.26.0")] +impl FusedIterator for Union<'_, T, S, A> +where + T: Eq + Hash, + S: BuildHasher, +{ +} + +#[stable(feature = "std_debug", since = "1.16.0")] +impl fmt::Debug for Union<'_, T, S, A> +where + T: fmt::Debug + Eq + Hash, + S: BuildHasher, + A: Allocator, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.clone()).finish() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, T, S, A> Iterator for Union<'a, T, S, A> +where + T: Eq + Hash, + S: BuildHasher, + A: Allocator, +{ + type Item = &'a T; + + #[inline] + fn next(&mut self) -> Option<&'a T> { + self.iter.next() + } + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } + #[inline] + fn count(self) -> usize { + self.iter.count() + } + #[inline] + fn fold(self, init: B, f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.iter.fold(init, f) + } +} + +/// A view into a single entry in a set, which may either be vacant or occupied. +/// +/// This `enum` is constructed from the [`entry`] method on [`HashSet`]. +/// +/// [`HashSet`]: struct.HashSet.html +/// [`entry`]: struct.HashSet.html#method.entry +/// +/// # Examples +/// +/// ``` +/// #![feature(hash_set_entry)] +/// +/// use std::collections::hash_set::HashSet; +/// +/// let mut set = HashSet::new(); +/// set.extend(["a", "b", "c"]); +/// assert_eq!(set.len(), 3); +/// +/// // Existing value (insert) +/// let entry = set.entry("a"); +/// let _raw_o = entry.insert(); +/// assert_eq!(set.len(), 3); +/// // Nonexistent value (insert) +/// set.entry("d").insert(); +/// +/// // Existing value (or_insert) +/// set.entry("b").or_insert(); +/// // Nonexistent value (or_insert) +/// set.entry("e").or_insert(); +/// +/// println!("Our HashSet: {:?}", set); +/// +/// let mut vec: Vec<_> = set.iter().copied().collect(); +/// // The `Iter` iterator produces items in arbitrary order, so the +/// // items must be sorted to test them against a sorted array. +/// vec.sort_unstable(); +/// assert_eq!(vec, ["a", "b", "c", "d", "e"]); +/// ``` +#[unstable(feature = "hash_set_entry", issue = "60896")] +pub enum Entry< + 'a, + T, + S, + #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, +> { + /// An occupied entry. + /// + /// # Examples + /// + /// ``` + /// #![feature(hash_set_entry)] + /// + /// use std::collections::hash_set::{Entry, HashSet}; + /// + /// let mut set = HashSet::from(["a", "b"]); + /// + /// match set.entry("a") { + /// Entry::Vacant(_) => unreachable!(), + /// Entry::Occupied(_) => { } + /// } + /// ``` + Occupied(OccupiedEntry<'a, T, S, A>), + + /// A vacant entry. + /// + /// # Examples + /// + /// ``` + /// #![feature(hash_set_entry)] + /// + /// use std::collections::hash_set::{Entry, HashSet}; + /// + /// let mut set = HashSet::new(); + /// + /// match set.entry("a") { + /// Entry::Occupied(_) => unreachable!(), + /// Entry::Vacant(_) => { } + /// } + /// ``` + Vacant(VacantEntry<'a, T, S, A>), +} + +#[unstable(feature = "hash_set_entry", issue = "60896")] +impl fmt::Debug for Entry<'_, T, S, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match *self { + Entry::Vacant(ref v) => f.debug_tuple("Entry").field(v).finish(), + Entry::Occupied(ref o) => f.debug_tuple("Entry").field(o).finish(), + } + } +} + +/// A view into an occupied entry in a `HashSet`. +/// It is part of the [`Entry`] enum. +/// +/// [`Entry`]: enum.Entry.html +/// +/// # Examples +/// +/// ``` +/// #![feature(hash_set_entry)] +/// +/// use std::collections::hash_set::{Entry, HashSet}; +/// +/// let mut set = HashSet::new(); +/// set.extend(["a", "b", "c"]); +/// +/// let _entry_o = set.entry("a").insert(); +/// assert_eq!(set.len(), 3); +/// +/// // Existing key +/// match set.entry("a") { +/// Entry::Vacant(_) => unreachable!(), +/// Entry::Occupied(view) => { +/// assert_eq!(view.get(), &"a"); +/// } +/// } +/// +/// assert_eq!(set.len(), 3); +/// +/// // Existing key (take) +/// match set.entry("c") { +/// Entry::Vacant(_) => unreachable!(), +/// Entry::Occupied(view) => { +/// assert_eq!(view.remove(), "c"); +/// } +/// } +/// assert_eq!(set.get(&"c"), None); +/// assert_eq!(set.len(), 2); +/// ``` +#[unstable(feature = "hash_set_entry", issue = "60896")] +pub struct OccupiedEntry< + 'a, + T, + S, + #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, +> { + base: base::OccupiedEntry<'a, T, S, A>, +} + +#[unstable(feature = "hash_set_entry", issue = "60896")] +impl fmt::Debug for OccupiedEntry<'_, T, S, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("OccupiedEntry").field("value", self.get()).finish() + } +} + +/// A view into a vacant entry in a `HashSet`. +/// It is part of the [`Entry`] enum. +/// +/// [`Entry`]: enum.Entry.html +/// +/// # Examples +/// +/// ``` +/// #![feature(hash_set_entry)] +/// +/// use std::collections::hash_set::{Entry, HashSet}; +/// +/// let mut set = HashSet::<&str>::new(); +/// +/// let entry_v = match set.entry("a") { +/// Entry::Vacant(view) => view, +/// Entry::Occupied(_) => unreachable!(), +/// }; +/// entry_v.insert(); +/// assert!(set.contains("a") && set.len() == 1); +/// +/// // Nonexistent key (insert) +/// match set.entry("b") { +/// Entry::Vacant(view) => view.insert(), +/// Entry::Occupied(_) => unreachable!(), +/// } +/// assert!(set.contains("b") && set.len() == 2); +/// ``` +#[unstable(feature = "hash_set_entry", issue = "60896")] +pub struct VacantEntry< + 'a, + T, + S, + #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, +> { + base: base::VacantEntry<'a, T, S, A>, +} + +#[unstable(feature = "hash_set_entry", issue = "60896")] +impl fmt::Debug for VacantEntry<'_, T, S, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_tuple("VacantEntry").field(self.get()).finish() + } +} + +impl<'a, T, S, A: Allocator> Entry<'a, T, S, A> { + /// Sets the value of the entry, and returns an OccupiedEntry. + /// + /// # Examples + /// + /// ``` + /// #![feature(hash_set_entry)] + /// + /// use std::collections::HashSet; + /// + /// let mut set = HashSet::new(); + /// let entry = set.entry("horseyland").insert(); + /// + /// assert_eq!(entry.get(), &"horseyland"); + /// ``` + #[inline] + #[unstable(feature = "hash_set_entry", issue = "60896")] + pub fn insert(self) -> OccupiedEntry<'a, T, S, A> + where + T: Hash, + S: BuildHasher, + { + match self { + Entry::Occupied(entry) => entry, + Entry::Vacant(entry) => entry.insert_entry(), + } + } + + /// Ensures a value is in the entry by inserting if it was vacant. + /// + /// # Examples + /// + /// ``` + /// #![feature(hash_set_entry)] + /// + /// use std::collections::HashSet; + /// + /// let mut set = HashSet::new(); + /// + /// // nonexistent key + /// set.entry("poneyland").or_insert(); + /// assert!(set.contains("poneyland")); + /// + /// // existing key + /// set.entry("poneyland").or_insert(); + /// assert!(set.contains("poneyland")); + /// assert_eq!(set.len(), 1); + /// ``` + #[inline] + #[unstable(feature = "hash_set_entry", issue = "60896")] + pub fn or_insert(self) + where + T: Hash, + S: BuildHasher, + { + if let Entry::Vacant(entry) = self { + entry.insert(); + } + } + + /// Returns a reference to this entry's value. + /// + /// # Examples + /// + /// ``` + /// #![feature(hash_set_entry)] + /// + /// use std::collections::HashSet; + /// + /// let mut set = HashSet::new(); + /// set.entry("poneyland").or_insert(); + /// + /// // existing key + /// assert_eq!(set.entry("poneyland").get(), &"poneyland"); + /// // nonexistent key + /// assert_eq!(set.entry("horseland").get(), &"horseland"); + /// ``` + #[inline] + #[unstable(feature = "hash_set_entry", issue = "60896")] + pub fn get(&self) -> &T { + match *self { + Entry::Occupied(ref entry) => entry.get(), + Entry::Vacant(ref entry) => entry.get(), + } + } +} + +impl OccupiedEntry<'_, T, S, A> { + /// Gets a reference to the value in the entry. + /// + /// # Examples + /// + /// ``` + /// #![feature(hash_set_entry)] + /// + /// use std::collections::hash_set::{Entry, HashSet}; + /// + /// let mut set = HashSet::new(); + /// set.entry("poneyland").or_insert(); + /// + /// match set.entry("poneyland") { + /// Entry::Vacant(_) => panic!(), + /// Entry::Occupied(entry) => assert_eq!(entry.get(), &"poneyland"), + /// } + /// ``` + #[inline] + #[unstable(feature = "hash_set_entry", issue = "60896")] + pub fn get(&self) -> &T { + self.base.get() + } + + /// Takes the value out of the entry, and returns it. + /// Keeps the allocated memory for reuse. + /// + /// # Examples + /// + /// ``` + /// #![feature(hash_set_entry)] + /// + /// use std::collections::HashSet; + /// use std::collections::hash_set::Entry; + /// + /// let mut set = HashSet::new(); + /// // The set is empty + /// assert!(set.is_empty() && set.capacity() == 0); + /// + /// set.entry("poneyland").or_insert(); + /// let capacity_before_remove = set.capacity(); + /// + /// if let Entry::Occupied(o) = set.entry("poneyland") { + /// assert_eq!(o.remove(), "poneyland"); + /// } + /// + /// assert_eq!(set.contains("poneyland"), false); + /// // Now set hold none elements but capacity is equal to the old one + /// assert!(set.len() == 0 && set.capacity() == capacity_before_remove); + /// ``` + #[inline] + #[unstable(feature = "hash_set_entry", issue = "60896")] + pub fn remove(self) -> T { + self.base.remove() + } +} + +impl<'a, T, S, A: Allocator> VacantEntry<'a, T, S, A> { + /// Gets a reference to the value that would be used when inserting + /// through the `VacantEntry`. + /// + /// # Examples + /// + /// ``` + /// #![feature(hash_set_entry)] + /// + /// use std::collections::HashSet; + /// + /// let mut set = HashSet::new(); + /// assert_eq!(set.entry("poneyland").get(), &"poneyland"); + /// ``` + #[inline] + #[unstable(feature = "hash_set_entry", issue = "60896")] + pub fn get(&self) -> &T { + self.base.get() + } + + /// Take ownership of the value. + /// + /// # Examples + /// + /// ``` + /// #![feature(hash_set_entry)] + /// + /// use std::collections::hash_set::{Entry, HashSet}; + /// + /// let mut set = HashSet::new(); + /// + /// match set.entry("poneyland") { + /// Entry::Occupied(_) => panic!(), + /// Entry::Vacant(v) => assert_eq!(v.into_value(), "poneyland"), + /// } + /// ``` + #[inline] + #[unstable(feature = "hash_set_entry", issue = "60896")] + pub fn into_value(self) -> T { + self.base.into_value() + } + + /// Sets the value of the entry with the VacantEntry's value. + /// + /// # Examples + /// + /// ``` + /// #![feature(hash_set_entry)] + /// + /// use std::collections::HashSet; + /// use std::collections::hash_set::Entry; + /// + /// let mut set = HashSet::new(); + /// + /// if let Entry::Vacant(o) = set.entry("poneyland") { + /// o.insert(); + /// } + /// assert!(set.contains("poneyland")); + /// ``` + #[inline] + #[unstable(feature = "hash_set_entry", issue = "60896")] + pub fn insert(self) + where + T: Hash, + S: BuildHasher, + { + self.base.insert(); + } + + #[inline] + fn insert_entry(self) -> OccupiedEntry<'a, T, S, A> + where + T: Hash, + S: BuildHasher, + { + OccupiedEntry { base: self.base.insert() } + } +} + +#[allow(dead_code)] +fn assert_covariance() { + fn set<'new>(v: HashSet<&'static str>) -> HashSet<&'new str> { + v + } + fn iter<'a, 'new>(v: Iter<'a, &'static str>) -> Iter<'a, &'new str> { + v + } + fn into_iter<'new>(v: IntoIter<&'static str>) -> IntoIter<&'new str> { + v + } + fn difference<'a, 'new>( + v: Difference<'a, &'static str, RandomState>, + ) -> Difference<'a, &'new str, RandomState> { + v + } + fn symmetric_difference<'a, 'new>( + v: SymmetricDifference<'a, &'static str, RandomState>, + ) -> SymmetricDifference<'a, &'new str, RandomState> { + v + } + fn intersection<'a, 'new>( + v: Intersection<'a, &'static str, RandomState>, + ) -> Intersection<'a, &'new str, RandomState> { + v + } + fn union<'a, 'new>( + v: Union<'a, &'static str, RandomState>, + ) -> Union<'a, &'new str, RandomState> { + v + } + fn drain<'new>(d: Drain<'static, &'static str>) -> Drain<'new, &'new str> { + d + } +} diff --git a/crates/std/src/collections/mod.rs b/crates/std/src/collections/mod.rs new file mode 100644 index 0000000..d755d75 --- /dev/null +++ b/crates/std/src/collections/mod.rs @@ -0,0 +1,6 @@ +use core::marker::PhantomData; + +pub struct HashMap { + _phantom: PhantomData<(K, V, T)>, +} +pub use alloc_crate::collections; diff --git a/crates/std/src/env.rs b/crates/std/src/env.rs new file mode 100644 index 0000000..469e4a8 --- /dev/null +++ b/crates/std/src/env.rs @@ -0,0 +1,5 @@ +use crate::ffi::OsString; + +pub fn var_os(s: &str) -> Option { + None +} diff --git a/crates/std/src/io.rs b/crates/std/src/io.rs index 13433b7..11fb8dc 100644 --- a/crates/std/src/io.rs +++ b/crates/std/src/io.rs @@ -9,7 +9,7 @@ pub mod copy; pub mod cursor; pub mod impls; pub mod pipe; -// pub mod stdio; +pub mod stdio; pub mod prelude; pub mod util; @@ -18,7 +18,9 @@ use crate::ops::{Deref, DerefMut}; use crate::{cmp, fmt, slice, str, sys}; #[unstable(feature = "read_buf", issue = "78485")] pub use core::io::{BorrowedBuf, BorrowedCursor}; +pub use cursor::Cursor; use core::slice::memchr; +pub use stdio::try_set_output_capture; use crate::fs::File; use io::IoBase; diff --git a/crates/std/src/io/stdio.rs b/crates/std/src/io/stdio.rs index 91211ab..689d0b5 100644 --- a/crates/std/src/io/stdio.rs +++ b/crates/std/src/io/stdio.rs @@ -1,7 +1,7 @@ #![cfg_attr(test, allow(unused))] -#[cfg(test)] -mod tests; +// #[cfg(test)] +// mod tests; use crate::cell::{Cell, RefCell}; use crate::fmt; @@ -10,7 +10,7 @@ use crate::io::prelude::*; use crate::io::{ self, BorrowedCursor, BufReader, IoSlice, IoSliceMut, LineWriter, Lines, SpecReadByte, }; -use core::panic::{RefUnwindSafe, UnwindSafe}; +use crate::panic::{RefUnwindSafe, UnwindSafe}; use crate::sync::atomic::{Atomic, AtomicBool, Ordering}; use crate::sync::{Arc, Mutex, MutexGuard, OnceLock, ReentrantLock, ReentrantLockGuard}; use crate::sys::stdio; @@ -18,1105 +18,1105 @@ use crate::thread::AccessError; type LocalStream = Arc>>; -thread_local! { - /// Used by the test crate to capture the output of the print macros and panics. - static OUTPUT_CAPTURE: Cell> = const { - Cell::new(None) - } -} - -/// Flag to indicate OUTPUT_CAPTURE is used. -/// -/// If it is None and was never set on any thread, this flag is set to false, -/// and OUTPUT_CAPTURE can be safely ignored on all threads, saving some time -/// and memory registering an unused thread local. -/// -/// Note about memory ordering: This contains information about whether a -/// thread local variable might be in use. Although this is a global flag, the -/// memory ordering between threads does not matter: we only want this flag to -/// have a consistent order between set_output_capture and print_to *within -/// the same thread*. Within the same thread, things always have a perfectly -/// consistent order. So Ordering::Relaxed is fine. -static OUTPUT_CAPTURE_USED: Atomic = AtomicBool::new(false); - -/// A handle to a raw instance of the standard input stream of this process. -/// -/// This handle is not synchronized or buffered in any fashion. Constructed via -/// the `std::io::stdio::stdin_raw` function. -struct StdinRaw(stdio::Stdin); - -/// A handle to a raw instance of the standard output stream of this process. -/// -/// This handle is not synchronized or buffered in any fashion. Constructed via -/// the `std::io::stdio::stdout_raw` function. -struct StdoutRaw(stdio::Stdout); - -/// A handle to a raw instance of the standard output stream of this process. -/// -/// This handle is not synchronized or buffered in any fashion. Constructed via -/// the `std::io::stdio::stderr_raw` function. -struct StderrRaw(stdio::Stderr); - -/// Constructs a new raw handle to the standard input of this process. -/// -/// The returned handle does not interact with any other handles created nor -/// handles returned by `std::io::stdin`. Data buffered by the `std::io::stdin` -/// handles is **not** available to raw handles returned from this function. -/// -/// The returned handle has no external synchronization or buffering. -#[unstable(feature = "libstd_sys_internals", issue = "none")] -const fn stdin_raw() -> StdinRaw { - StdinRaw(stdio::Stdin::new()) -} - -/// Constructs a new raw handle to the standard output stream of this process. -/// -/// The returned handle does not interact with any other handles created nor -/// handles returned by `std::io::stdout`. Note that data is buffered by the -/// `std::io::stdout` handles so writes which happen via this raw handle may -/// appear before previous writes. -/// -/// The returned handle has no external synchronization or buffering layered on -/// top. -#[unstable(feature = "libstd_sys_internals", issue = "none")] -const fn stdout_raw() -> StdoutRaw { - StdoutRaw(stdio::Stdout::new()) -} - -/// Constructs a new raw handle to the standard error stream of this process. -/// -/// The returned handle does not interact with any other handles created nor -/// handles returned by `std::io::stderr`. -/// -/// The returned handle has no external synchronization or buffering layered on -/// top. -#[unstable(feature = "libstd_sys_internals", issue = "none")] -const fn stderr_raw() -> StderrRaw { - StderrRaw(stdio::Stderr::new()) -} - -impl Read for StdinRaw { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - handle_ebadf(self.0.read(buf), || Ok(0)) - } - - fn read_buf(&mut self, buf: BorrowedCursor<'_>) -> io::Result<()> { - handle_ebadf(self.0.read_buf(buf), || Ok(())) - } - - fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { - handle_ebadf(self.0.read_vectored(bufs), || Ok(0)) - } - - #[inline] - fn is_read_vectored(&self) -> bool { - self.0.is_read_vectored() - } - - fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> { - if buf.is_empty() { - return Ok(()); - } - handle_ebadf(self.0.read_exact(buf), || Err(io::Error::READ_EXACT_EOF)) - } - - fn read_buf_exact(&mut self, buf: BorrowedCursor<'_>) -> io::Result<()> { - if buf.capacity() == 0 { - return Ok(()); - } - handle_ebadf(self.0.read_buf_exact(buf), || Err(io::Error::READ_EXACT_EOF)) - } - - fn read_to_end(&mut self, buf: &mut Vec) -> io::Result { - handle_ebadf(self.0.read_to_end(buf), || Ok(0)) - } - - fn read_to_string(&mut self, buf: &mut String) -> io::Result { - handle_ebadf(self.0.read_to_string(buf), || Ok(0)) - } -} - -impl Write for StdoutRaw { - fn write(&mut self, buf: &[u8]) -> io::Result { - handle_ebadf(self.0.write(buf), || Ok(buf.len())) - } - - fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { - let total = || Ok(bufs.iter().map(|b| b.len()).sum()); - handle_ebadf(self.0.write_vectored(bufs), total) - } - - #[inline] - fn is_write_vectored(&self) -> bool { - self.0.is_write_vectored() - } - - fn flush(&mut self) -> io::Result<()> { - handle_ebadf(self.0.flush(), || Ok(())) - } - - fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { - handle_ebadf(self.0.write_all(buf), || Ok(())) - } - - fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> { - handle_ebadf(self.0.write_all_vectored(bufs), || Ok(())) - } - - fn write_fmt(&mut self, fmt: fmt::Arguments<'_>) -> io::Result<()> { - handle_ebadf(self.0.write_fmt(fmt), || Ok(())) - } -} - -impl Write for StderrRaw { - fn write(&mut self, buf: &[u8]) -> io::Result { - handle_ebadf(self.0.write(buf), || Ok(buf.len())) - } - - fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { - let total = || Ok(bufs.iter().map(|b| b.len()).sum()); - handle_ebadf(self.0.write_vectored(bufs), total) - } - - #[inline] - fn is_write_vectored(&self) -> bool { - self.0.is_write_vectored() - } - - fn flush(&mut self) -> io::Result<()> { - handle_ebadf(self.0.flush(), || Ok(())) - } - - fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { - handle_ebadf(self.0.write_all(buf), || Ok(())) - } - - fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> { - handle_ebadf(self.0.write_all_vectored(bufs), || Ok(())) - } - - fn write_fmt(&mut self, fmt: fmt::Arguments<'_>) -> io::Result<()> { - handle_ebadf(self.0.write_fmt(fmt), || Ok(())) - } -} - -fn handle_ebadf(r: io::Result, default: impl FnOnce() -> io::Result) -> io::Result { - match r { - Err(ref e) if stdio::is_ebadf(e) => default(), - r => r, - } -} - -/// A handle to the standard input stream of a process. -/// -/// Each handle is a shared reference to a global buffer of input data to this -/// process. A handle can be `lock`'d to gain full access to [`BufRead`] methods -/// (e.g., `.lines()`). Reads to this handle are otherwise locked with respect -/// to other reads. -/// -/// This handle implements the `Read` trait, but beware that concurrent reads -/// of `Stdin` must be executed with care. -/// -/// Created by the [`io::stdin`] method. -/// -/// [`io::stdin`]: stdin -/// -/// ### Note: Windows Portability Considerations -/// -/// When operating in a console, the Windows implementation of this stream does not support -/// non-UTF-8 byte sequences. Attempting to read bytes that are not valid UTF-8 will return -/// an error. -/// -/// In a process with a detached console, such as one using -/// `#![windows_subsystem = "windows"]`, or in a child process spawned from such a process, -/// the contained handle will be null. In such cases, the standard library's `Read` and -/// `Write` will do nothing and silently succeed. All other I/O operations, via the -/// standard library or via raw Windows API calls, will fail. -/// -/// # Examples -/// -/// ```no_run -/// use std::io; -/// -/// fn main() -> io::Result<()> { -/// let mut buffer = String::new(); -/// let stdin = io::stdin(); // We get `Stdin` here. -/// stdin.read_line(&mut buffer)?; -/// Ok(()) -/// } -/// ``` -#[stable(feature = "rust1", since = "1.0.0")] -#[cfg_attr(not(test), rustc_diagnostic_item = "Stdin")] -pub struct Stdin { - inner: &'static Mutex>, -} - -/// A locked reference to the [`Stdin`] handle. -/// -/// This handle implements both the [`Read`] and [`BufRead`] traits, and -/// is constructed via the [`Stdin::lock`] method. -/// -/// ### Note: Windows Portability Considerations -/// -/// When operating in a console, the Windows implementation of this stream does not support -/// non-UTF-8 byte sequences. Attempting to read bytes that are not valid UTF-8 will return -/// an error. -/// -/// In a process with a detached console, such as one using -/// `#![windows_subsystem = "windows"]`, or in a child process spawned from such a process, -/// the contained handle will be null. In such cases, the standard library's `Read` and -/// `Write` will do nothing and silently succeed. All other I/O operations, via the -/// standard library or via raw Windows API calls, will fail. -/// -/// # Examples -/// -/// ```no_run -/// use std::io::{self, BufRead}; -/// -/// fn main() -> io::Result<()> { -/// let mut buffer = String::new(); -/// let stdin = io::stdin(); // We get `Stdin` here. -/// { -/// let mut handle = stdin.lock(); // We get `StdinLock` here. -/// handle.read_line(&mut buffer)?; -/// } // `StdinLock` is dropped here. -/// Ok(()) -/// } -/// ``` -#[must_use = "if unused stdin will immediately unlock"] -#[stable(feature = "rust1", since = "1.0.0")] -pub struct StdinLock<'a> { - inner: MutexGuard<'a, BufReader>, -} - -/// Constructs a new handle to the standard input of the current process. -/// -/// Each handle returned is a reference to a shared global buffer whose access -/// is synchronized via a mutex. If you need more explicit control over -/// locking, see the [`Stdin::lock`] method. -/// -/// ### Note: Windows Portability Considerations -/// -/// When operating in a console, the Windows implementation of this stream does not support -/// non-UTF-8 byte sequences. Attempting to read bytes that are not valid UTF-8 will return -/// an error. -/// -/// In a process with a detached console, such as one using -/// `#![windows_subsystem = "windows"]`, or in a child process spawned from such a process, -/// the contained handle will be null. In such cases, the standard library's `Read` and -/// `Write` will do nothing and silently succeed. All other I/O operations, via the -/// standard library or via raw Windows API calls, will fail. -/// -/// # Examples -/// -/// Using implicit synchronization: -/// -/// ```no_run -/// use std::io; -/// -/// fn main() -> io::Result<()> { -/// let mut buffer = String::new(); -/// io::stdin().read_line(&mut buffer)?; -/// Ok(()) -/// } -/// ``` -/// -/// Using explicit synchronization: -/// -/// ```no_run -/// use std::io::{self, BufRead}; -/// -/// fn main() -> io::Result<()> { -/// let mut buffer = String::new(); -/// let stdin = io::stdin(); -/// let mut handle = stdin.lock(); -/// -/// handle.read_line(&mut buffer)?; -/// Ok(()) -/// } -/// ``` -#[must_use] -#[stable(feature = "rust1", since = "1.0.0")] -pub fn stdin() -> Stdin { - static INSTANCE: OnceLock>> = OnceLock::new(); - Stdin { - inner: INSTANCE.get_or_init(|| { - Mutex::new(BufReader::with_capacity(stdio::STDIN_BUF_SIZE, stdin_raw())) - }), - } -} - -impl Stdin { - /// Locks this handle to the standard input stream, returning a readable - /// guard. - /// - /// The lock is released when the returned lock goes out of scope. The - /// returned guard also implements the [`Read`] and [`BufRead`] traits for - /// accessing the underlying data. - /// - /// # Examples - /// - /// ```no_run - /// use std::io::{self, BufRead}; - /// - /// fn main() -> io::Result<()> { - /// let mut buffer = String::new(); - /// let stdin = io::stdin(); - /// let mut handle = stdin.lock(); - /// - /// handle.read_line(&mut buffer)?; - /// Ok(()) - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn lock(&self) -> StdinLock<'static> { - // Locks this handle with 'static lifetime. This depends on the - // implementation detail that the underlying `Mutex` is static. - StdinLock { inner: self.inner.lock().unwrap_or_else(|e| e.into_inner()) } - } - - /// Locks this handle and reads a line of input, appending it to the specified buffer. - /// - /// For detailed semantics of this method, see the documentation on - /// [`BufRead::read_line`]. In particular: - /// * Previous content of the buffer will be preserved. To avoid appending - /// to the buffer, you need to [`clear`] it first. - /// * The trailing newline character, if any, is included in the buffer. - /// - /// [`clear`]: String::clear - /// - /// # Examples - /// - /// ```no_run - /// use std::io; - /// - /// let mut input = String::new(); - /// match io::stdin().read_line(&mut input) { - /// Ok(n) => { - /// println!("{n} bytes read"); - /// println!("{input}"); - /// } - /// Err(error) => println!("error: {error}"), - /// } - /// ``` - /// - /// You can run the example one of two ways: - /// - /// - Pipe some text to it, e.g., `printf foo | path/to/executable` - /// - Give it text interactively by running the executable directly, - /// in which case it will wait for the Enter key to be pressed before - /// continuing - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_confusables("get_line")] - pub fn read_line(&self, buf: &mut String) -> io::Result { - self.lock().read_line(buf) - } - - /// Consumes this handle and returns an iterator over input lines. - /// - /// For detailed semantics of this method, see the documentation on - /// [`BufRead::lines`]. - /// - /// # Examples - /// - /// ```no_run - /// use std::io; - /// - /// let lines = io::stdin().lines(); - /// for line in lines { - /// println!("got a line: {}", line.unwrap()); - /// } - /// ``` - #[must_use = "`self` will be dropped if the result is not used"] - #[stable(feature = "stdin_forwarders", since = "1.62.0")] - pub fn lines(self) -> Lines> { - self.lock().lines() - } -} - -#[stable(feature = "std_debug", since = "1.16.0")] -impl fmt::Debug for Stdin { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Stdin").finish_non_exhaustive() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Read for Stdin { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - self.lock().read(buf) - } - fn read_buf(&mut self, buf: BorrowedCursor<'_>) -> io::Result<()> { - self.lock().read_buf(buf) - } - fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { - self.lock().read_vectored(bufs) - } - #[inline] - fn is_read_vectored(&self) -> bool { - self.lock().is_read_vectored() - } - fn read_to_end(&mut self, buf: &mut Vec) -> io::Result { - self.lock().read_to_end(buf) - } - fn read_to_string(&mut self, buf: &mut String) -> io::Result { - self.lock().read_to_string(buf) - } - fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> { - self.lock().read_exact(buf) - } - fn read_buf_exact(&mut self, cursor: BorrowedCursor<'_>) -> io::Result<()> { - self.lock().read_buf_exact(cursor) - } -} - -#[stable(feature = "read_shared_stdin", since = "1.78.0")] -impl Read for &Stdin { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - self.lock().read(buf) - } - fn read_buf(&mut self, buf: BorrowedCursor<'_>) -> io::Result<()> { - self.lock().read_buf(buf) - } - fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { - self.lock().read_vectored(bufs) - } - #[inline] - fn is_read_vectored(&self) -> bool { - self.lock().is_read_vectored() - } - fn read_to_end(&mut self, buf: &mut Vec) -> io::Result { - self.lock().read_to_end(buf) - } - fn read_to_string(&mut self, buf: &mut String) -> io::Result { - self.lock().read_to_string(buf) - } - fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> { - self.lock().read_exact(buf) - } - fn read_buf_exact(&mut self, cursor: BorrowedCursor<'_>) -> io::Result<()> { - self.lock().read_buf_exact(cursor) - } -} - -// only used by platform-dependent io::copy specializations, i.e. unused on some platforms -#[cfg(any(target_os = "linux", target_os = "android"))] -impl StdinLock<'_> { - pub(crate) fn as_mut_buf(&mut self) -> &mut BufReader { - &mut self.inner - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Read for StdinLock<'_> { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - self.inner.read(buf) - } - - fn read_buf(&mut self, buf: BorrowedCursor<'_>) -> io::Result<()> { - self.inner.read_buf(buf) - } - - fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { - self.inner.read_vectored(bufs) - } - - #[inline] - fn is_read_vectored(&self) -> bool { - self.inner.is_read_vectored() - } - - fn read_to_end(&mut self, buf: &mut Vec) -> io::Result { - self.inner.read_to_end(buf) - } - - fn read_to_string(&mut self, buf: &mut String) -> io::Result { - self.inner.read_to_string(buf) - } - - fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> { - self.inner.read_exact(buf) - } - - fn read_buf_exact(&mut self, cursor: BorrowedCursor<'_>) -> io::Result<()> { - self.inner.read_buf_exact(cursor) - } -} - -impl SpecReadByte for StdinLock<'_> { - #[inline] - fn spec_read_byte(&mut self) -> Option> { - BufReader::spec_read_byte(&mut *self.inner) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl BufRead for StdinLock<'_> { - fn fill_buf(&mut self) -> io::Result<&[u8]> { - self.inner.fill_buf() - } - - fn consume(&mut self, n: usize) { - self.inner.consume(n) - } - - fn read_until(&mut self, byte: u8, buf: &mut Vec) -> io::Result { - self.inner.read_until(byte, buf) - } - - fn read_line(&mut self, buf: &mut String) -> io::Result { - self.inner.read_line(buf) - } -} - -#[stable(feature = "std_debug", since = "1.16.0")] -impl fmt::Debug for StdinLock<'_> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("StdinLock").finish_non_exhaustive() - } -} - -/// A handle to the global standard output stream of the current process. -/// -/// Each handle shares a global buffer of data to be written to the standard -/// output stream. Access is also synchronized via a lock and explicit control -/// over locking is available via the [`lock`] method. -/// -/// By default, the handle is line-buffered when connected to a terminal, meaning -/// it flushes automatically when a newline (`\n`) is encountered. For immediate -/// output, you can manually call the [`flush`] method. When the handle goes out -/// of scope, the buffer is automatically flushed. -/// -/// Created by the [`io::stdout`] method. -/// -/// ### Note: Windows Portability Considerations -/// -/// When operating in a console, the Windows implementation of this stream does not support -/// non-UTF-8 byte sequences. Attempting to write bytes that are not valid UTF-8 will return -/// an error. -/// -/// In a process with a detached console, such as one using -/// `#![windows_subsystem = "windows"]`, or in a child process spawned from such a process, -/// the contained handle will be null. In such cases, the standard library's `Read` and -/// `Write` will do nothing and silently succeed. All other I/O operations, via the -/// standard library or via raw Windows API calls, will fail. -/// -/// [`lock`]: Stdout::lock -/// [`flush`]: Write::flush -/// [`io::stdout`]: stdout -#[stable(feature = "rust1", since = "1.0.0")] -pub struct Stdout { - // FIXME: this should be LineWriter or BufWriter depending on the state of - // stdout (tty or not). Note that if this is not line buffered it - // should also flush-on-panic or some form of flush-on-abort. - inner: &'static ReentrantLock>>, -} - -/// A locked reference to the [`Stdout`] handle. -/// -/// This handle implements the [`Write`] trait, and is constructed via -/// the [`Stdout::lock`] method. See its documentation for more. -/// -/// By default, the handle is line-buffered when connected to a terminal, meaning -/// it flushes automatically when a newline (`\n`) is encountered. For immediate -/// output, you can manually call the [`flush`] method. When the handle goes out -/// of scope, the buffer is automatically flushed. -/// -/// ### Note: Windows Portability Considerations -/// -/// When operating in a console, the Windows implementation of this stream does not support -/// non-UTF-8 byte sequences. Attempting to write bytes that are not valid UTF-8 will return -/// an error. -/// -/// In a process with a detached console, such as one using -/// `#![windows_subsystem = "windows"]`, or in a child process spawned from such a process, -/// the contained handle will be null. In such cases, the standard library's `Read` and -/// `Write` will do nothing and silently succeed. All other I/O operations, via the -/// standard library or via raw Windows API calls, will fail. -/// -/// [`flush`]: Write::flush -#[must_use = "if unused stdout will immediately unlock"] -#[stable(feature = "rust1", since = "1.0.0")] -pub struct StdoutLock<'a> { - inner: ReentrantLockGuard<'a, RefCell>>, -} - -static STDOUT: OnceLock>>> = OnceLock::new(); - -/// Constructs a new handle to the standard output of the current process. -/// -/// Each handle returned is a reference to a shared global buffer whose access -/// is synchronized via a mutex. If you need more explicit control over -/// locking, see the [`Stdout::lock`] method. -/// -/// By default, the handle is line-buffered when connected to a terminal, meaning -/// it flushes automatically when a newline (`\n`) is encountered. For immediate -/// output, you can manually call the [`flush`] method. When the handle goes out -/// of scope, the buffer is automatically flushed. -/// -/// ### Note: Windows Portability Considerations -/// -/// When operating in a console, the Windows implementation of this stream does not support -/// non-UTF-8 byte sequences. Attempting to write bytes that are not valid UTF-8 will return -/// an error. -/// -/// In a process with a detached console, such as one using -/// `#![windows_subsystem = "windows"]`, or in a child process spawned from such a process, -/// the contained handle will be null. In such cases, the standard library's `Read` and -/// `Write` will do nothing and silently succeed. All other I/O operations, via the -/// standard library or via raw Windows API calls, will fail. -/// -/// # Examples -/// -/// Using implicit synchronization: -/// -/// ```no_run -/// use std::io::{self, Write}; -/// -/// fn main() -> io::Result<()> { -/// io::stdout().write_all(b"hello world")?; -/// -/// Ok(()) -/// } -/// ``` -/// -/// Using explicit synchronization: -/// -/// ```no_run -/// use std::io::{self, Write}; -/// -/// fn main() -> io::Result<()> { -/// let stdout = io::stdout(); -/// let mut handle = stdout.lock(); -/// -/// handle.write_all(b"hello world")?; -/// -/// Ok(()) -/// } -/// ``` -/// -/// Ensuring output is flushed immediately: -/// -/// ```no_run -/// use std::io::{self, Write}; -/// -/// fn main() -> io::Result<()> { -/// let mut stdout = io::stdout(); -/// stdout.write_all(b"hello, ")?; -/// stdout.flush()?; // Manual flush -/// stdout.write_all(b"world!\n")?; // Automatically flushed -/// Ok(()) -/// } -/// ``` -/// -/// [`flush`]: Write::flush -#[must_use] -#[stable(feature = "rust1", since = "1.0.0")] -#[cfg_attr(not(test), rustc_diagnostic_item = "io_stdout")] -pub fn stdout() -> Stdout { - Stdout { - inner: STDOUT - .get_or_init(|| ReentrantLock::new(RefCell::new(LineWriter::new(stdout_raw())))), - } -} - -// Flush the data and disable buffering during shutdown -// by replacing the line writer by one with zero -// buffering capacity. -pub fn cleanup() { - let mut initialized = false; - let stdout = STDOUT.get_or_init(|| { - initialized = true; - ReentrantLock::new(RefCell::new(LineWriter::with_capacity(0, stdout_raw()))) - }); - - if !initialized { - // The buffer was previously initialized, overwrite it here. - // We use try_lock() instead of lock(), because someone - // might have leaked a StdoutLock, which would - // otherwise cause a deadlock here. - if let Some(lock) = stdout.try_lock() { - *lock.borrow_mut() = LineWriter::with_capacity(0, stdout_raw()); - } - } -} - -impl Stdout { - /// Locks this handle to the standard output stream, returning a writable - /// guard. - /// - /// The lock is released when the returned lock goes out of scope. The - /// returned guard also implements the `Write` trait for writing data. - /// - /// # Examples - /// - /// ```no_run - /// use std::io::{self, Write}; - /// - /// fn main() -> io::Result<()> { - /// let mut stdout = io::stdout().lock(); - /// - /// stdout.write_all(b"hello world")?; - /// - /// Ok(()) - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn lock(&self) -> StdoutLock<'static> { - // Locks this handle with 'static lifetime. This depends on the - // implementation detail that the underlying `ReentrantMutex` is - // static. - StdoutLock { inner: self.inner.lock() } - } -} - -#[stable(feature = "catch_unwind", since = "1.9.0")] -impl UnwindSafe for Stdout {} - -#[stable(feature = "catch_unwind", since = "1.9.0")] -impl RefUnwindSafe for Stdout {} - -#[stable(feature = "std_debug", since = "1.16.0")] -impl fmt::Debug for Stdout { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Stdout").finish_non_exhaustive() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Write for Stdout { - fn write(&mut self, buf: &[u8]) -> io::Result { - (&*self).write(buf) - } - fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { - (&*self).write_vectored(bufs) - } - #[inline] - fn is_write_vectored(&self) -> bool { - io::Write::is_write_vectored(&&*self) - } - fn flush(&mut self) -> io::Result<()> { - (&*self).flush() - } - fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { - (&*self).write_all(buf) - } - fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> { - (&*self).write_all_vectored(bufs) - } - fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> io::Result<()> { - (&*self).write_fmt(args) - } -} - -#[stable(feature = "write_mt", since = "1.48.0")] -impl Write for &Stdout { - fn write(&mut self, buf: &[u8]) -> io::Result { - self.lock().write(buf) - } - fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { - self.lock().write_vectored(bufs) - } - #[inline] - fn is_write_vectored(&self) -> bool { - self.lock().is_write_vectored() - } - fn flush(&mut self) -> io::Result<()> { - self.lock().flush() - } - fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { - self.lock().write_all(buf) - } - fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> { - self.lock().write_all_vectored(bufs) - } - fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> io::Result<()> { - self.lock().write_fmt(args) - } -} - -#[stable(feature = "catch_unwind", since = "1.9.0")] -impl UnwindSafe for StdoutLock<'_> {} - -#[stable(feature = "catch_unwind", since = "1.9.0")] -impl RefUnwindSafe for StdoutLock<'_> {} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Write for StdoutLock<'_> { - fn write(&mut self, buf: &[u8]) -> io::Result { - self.inner.borrow_mut().write(buf) - } - fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { - self.inner.borrow_mut().write_vectored(bufs) - } - #[inline] - fn is_write_vectored(&self) -> bool { - self.inner.borrow_mut().is_write_vectored() - } - fn flush(&mut self) -> io::Result<()> { - self.inner.borrow_mut().flush() - } - fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { - self.inner.borrow_mut().write_all(buf) - } - fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> { - self.inner.borrow_mut().write_all_vectored(bufs) - } -} - -#[stable(feature = "std_debug", since = "1.16.0")] -impl fmt::Debug for StdoutLock<'_> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("StdoutLock").finish_non_exhaustive() - } -} - -/// A handle to the standard error stream of a process. -/// -/// For more information, see the [`io::stderr`] method. -/// -/// [`io::stderr`]: stderr -/// -/// ### Note: Windows Portability Considerations -/// -/// When operating in a console, the Windows implementation of this stream does not support -/// non-UTF-8 byte sequences. Attempting to write bytes that are not valid UTF-8 will return -/// an error. -/// -/// In a process with a detached console, such as one using -/// `#![windows_subsystem = "windows"]`, or in a child process spawned from such a process, -/// the contained handle will be null. In such cases, the standard library's `Read` and -/// `Write` will do nothing and silently succeed. All other I/O operations, via the -/// standard library or via raw Windows API calls, will fail. -#[stable(feature = "rust1", since = "1.0.0")] -pub struct Stderr { - inner: &'static ReentrantLock>, -} - -/// A locked reference to the [`Stderr`] handle. -/// -/// This handle implements the [`Write`] trait and is constructed via -/// the [`Stderr::lock`] method. See its documentation for more. -/// -/// ### Note: Windows Portability Considerations -/// -/// When operating in a console, the Windows implementation of this stream does not support -/// non-UTF-8 byte sequences. Attempting to write bytes that are not valid UTF-8 will return -/// an error. -/// -/// In a process with a detached console, such as one using -/// `#![windows_subsystem = "windows"]`, or in a child process spawned from such a process, -/// the contained handle will be null. In such cases, the standard library's `Read` and -/// `Write` will do nothing and silently succeed. All other I/O operations, via the -/// standard library or via raw Windows API calls, will fail. -#[must_use = "if unused stderr will immediately unlock"] -#[stable(feature = "rust1", since = "1.0.0")] -pub struct StderrLock<'a> { - inner: ReentrantLockGuard<'a, RefCell>, -} - -/// Constructs a new handle to the standard error of the current process. -/// -/// This handle is not buffered. -/// -/// ### Note: Windows Portability Considerations -/// -/// When operating in a console, the Windows implementation of this stream does not support -/// non-UTF-8 byte sequences. Attempting to write bytes that are not valid UTF-8 will return -/// an error. -/// -/// In a process with a detached console, such as one using -/// `#![windows_subsystem = "windows"]`, or in a child process spawned from such a process, -/// the contained handle will be null. In such cases, the standard library's `Read` and -/// `Write` will do nothing and silently succeed. All other I/O operations, via the -/// standard library or via raw Windows API calls, will fail. -/// -/// # Examples -/// -/// Using implicit synchronization: -/// -/// ```no_run -/// use std::io::{self, Write}; -/// -/// fn main() -> io::Result<()> { -/// io::stderr().write_all(b"hello world")?; -/// -/// Ok(()) -/// } -/// ``` -/// -/// Using explicit synchronization: -/// -/// ```no_run -/// use std::io::{self, Write}; -/// -/// fn main() -> io::Result<()> { -/// let stderr = io::stderr(); -/// let mut handle = stderr.lock(); -/// -/// handle.write_all(b"hello world")?; -/// -/// Ok(()) -/// } -/// ``` -#[must_use] -#[stable(feature = "rust1", since = "1.0.0")] -#[cfg_attr(not(test), rustc_diagnostic_item = "io_stderr")] -pub fn stderr() -> Stderr { - // Note that unlike `stdout()` we don't use `at_exit` here to register a - // destructor. Stderr is not buffered, so there's no need to run a - // destructor for flushing the buffer - static INSTANCE: ReentrantLock> = - ReentrantLock::new(RefCell::new(stderr_raw())); - - Stderr { inner: &INSTANCE } -} - -impl Stderr { - /// Locks this handle to the standard error stream, returning a writable - /// guard. - /// - /// The lock is released when the returned lock goes out of scope. The - /// returned guard also implements the [`Write`] trait for writing data. - /// - /// # Examples - /// - /// ``` - /// use std::io::{self, Write}; - /// - /// fn foo() -> io::Result<()> { - /// let stderr = io::stderr(); - /// let mut handle = stderr.lock(); - /// - /// handle.write_all(b"hello world")?; - /// - /// Ok(()) - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn lock(&self) -> StderrLock<'static> { - // Locks this handle with 'static lifetime. This depends on the - // implementation detail that the underlying `ReentrantMutex` is - // static. - StderrLock { inner: self.inner.lock() } - } -} - -#[stable(feature = "catch_unwind", since = "1.9.0")] -impl UnwindSafe for Stderr {} - -#[stable(feature = "catch_unwind", since = "1.9.0")] -impl RefUnwindSafe for Stderr {} - -#[stable(feature = "std_debug", since = "1.16.0")] -impl fmt::Debug for Stderr { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Stderr").finish_non_exhaustive() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Write for Stderr { - fn write(&mut self, buf: &[u8]) -> io::Result { - (&*self).write(buf) - } - fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { - (&*self).write_vectored(bufs) - } - #[inline] - fn is_write_vectored(&self) -> bool { - io::Write::is_write_vectored(&&*self) - } - fn flush(&mut self) -> io::Result<()> { - (&*self).flush() - } - fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { - (&*self).write_all(buf) - } - fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> { - (&*self).write_all_vectored(bufs) - } - fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> io::Result<()> { - (&*self).write_fmt(args) - } -} - -#[stable(feature = "write_mt", since = "1.48.0")] -impl Write for &Stderr { - fn write(&mut self, buf: &[u8]) -> io::Result { - self.lock().write(buf) - } - fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { - self.lock().write_vectored(bufs) - } - #[inline] - fn is_write_vectored(&self) -> bool { - self.lock().is_write_vectored() - } - fn flush(&mut self) -> io::Result<()> { - self.lock().flush() - } - fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { - self.lock().write_all(buf) - } - fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> { - self.lock().write_all_vectored(bufs) - } - fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> io::Result<()> { - self.lock().write_fmt(args) - } -} - -#[stable(feature = "catch_unwind", since = "1.9.0")] -impl UnwindSafe for StderrLock<'_> {} - -#[stable(feature = "catch_unwind", since = "1.9.0")] -impl RefUnwindSafe for StderrLock<'_> {} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Write for StderrLock<'_> { - fn write(&mut self, buf: &[u8]) -> io::Result { - self.inner.borrow_mut().write(buf) - } - fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { - self.inner.borrow_mut().write_vectored(bufs) - } - #[inline] - fn is_write_vectored(&self) -> bool { - self.inner.borrow_mut().is_write_vectored() - } - fn flush(&mut self) -> io::Result<()> { - self.inner.borrow_mut().flush() - } - fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { - self.inner.borrow_mut().write_all(buf) - } - fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> { - self.inner.borrow_mut().write_all_vectored(bufs) - } -} - -#[stable(feature = "std_debug", since = "1.16.0")] -impl fmt::Debug for StderrLock<'_> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("StderrLock").finish_non_exhaustive() - } -} - -/// Sets the thread-local output capture buffer and returns the old one. -#[unstable( - feature = "internal_output_capture", - reason = "this function is meant for use in the test crate \ - and may disappear in the future", - issue = "none" -)] -#[doc(hidden)] -pub fn set_output_capture(sink: Option) -> Option { - try_set_output_capture(sink).expect( - "cannot access a Thread Local Storage value \ - during or after destruction", - ) -} +// thread_local! { +// /// Used by the test crate to capture the output of the print macros and panics. +// static OUTPUT_CAPTURE: Cell> = const { +// Cell::new(None) +// } +// } + +// /// Flag to indicate OUTPUT_CAPTURE is used. +// /// +// /// If it is None and was never set on any thread, this flag is set to false, +// /// and OUTPUT_CAPTURE can be safely ignored on all threads, saving some time +// /// and memory registering an unused thread local. +// /// +// /// Note about memory ordering: This contains information about whether a +// /// thread local variable might be in use. Although this is a global flag, the +// /// memory ordering between threads does not matter: we only want this flag to +// /// have a consistent order between set_output_capture and print_to *within +// /// the same thread*. Within the same thread, things always have a perfectly +// /// consistent order. So Ordering::Relaxed is fine. +// static OUTPUT_CAPTURE_USED: Atomic = AtomicBool::new(false); + +// /// A handle to a raw instance of the standard input stream of this process. +// /// +// /// This handle is not synchronized or buffered in any fashion. Constructed via +// /// the `std::io::stdio::stdin_raw` function. +// struct StdinRaw(stdio::Stdin); + +// /// A handle to a raw instance of the standard output stream of this process. +// /// +// /// This handle is not synchronized or buffered in any fashion. Constructed via +// /// the `std::io::stdio::stdout_raw` function. +// struct StdoutRaw(stdio::Stdout); + +// /// A handle to a raw instance of the standard output stream of this process. +// /// +// /// This handle is not synchronized or buffered in any fashion. Constructed via +// /// the `std::io::stdio::stderr_raw` function. +// struct StderrRaw(stdio::Stderr); + +// /// Constructs a new raw handle to the standard input of this process. +// /// +// /// The returned handle does not interact with any other handles created nor +// /// handles returned by `std::io::stdin`. Data buffered by the `std::io::stdin` +// /// handles is **not** available to raw handles returned from this function. +// /// +// /// The returned handle has no external synchronization or buffering. +// #[unstable(feature = "libstd_sys_internals", issue = "none")] +// const fn stdin_raw() -> StdinRaw { +// StdinRaw(stdio::Stdin::new()) +// } + +// /// Constructs a new raw handle to the standard output stream of this process. +// /// +// /// The returned handle does not interact with any other handles created nor +// /// handles returned by `std::io::stdout`. Note that data is buffered by the +// /// `std::io::stdout` handles so writes which happen via this raw handle may +// /// appear before previous writes. +// /// +// /// The returned handle has no external synchronization or buffering layered on +// /// top. +// #[unstable(feature = "libstd_sys_internals", issue = "none")] +// const fn stdout_raw() -> StdoutRaw { +// StdoutRaw(stdio::Stdout::new()) +// } + +// /// Constructs a new raw handle to the standard error stream of this process. +// /// +// /// The returned handle does not interact with any other handles created nor +// /// handles returned by `std::io::stderr`. +// /// +// /// The returned handle has no external synchronization or buffering layered on +// /// top. +// #[unstable(feature = "libstd_sys_internals", issue = "none")] +// const fn stderr_raw() -> StderrRaw { +// StderrRaw(stdio::Stderr::new()) +// } + +// impl Read for StdinRaw { +// fn read(&mut self, buf: &mut [u8]) -> io::Result { +// handle_ebadf(self.0.read(buf), || Ok(0)) +// } + +// fn read_buf(&mut self, buf: BorrowedCursor<'_>) -> io::Result<()> { +// handle_ebadf(self.0.read_buf(buf), || Ok(())) +// } + +// fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { +// handle_ebadf(self.0.read_vectored(bufs), || Ok(0)) +// } + +// #[inline] +// fn is_read_vectored(&self) -> bool { +// self.0.is_read_vectored() +// } + +// fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> { +// if buf.is_empty() { +// return Ok(()); +// } +// handle_ebadf(self.0.read_exact(buf), || Err(io::Error::READ_EXACT_EOF)) +// } + +// fn read_buf_exact(&mut self, buf: BorrowedCursor<'_>) -> io::Result<()> { +// if buf.capacity() == 0 { +// return Ok(()); +// } +// handle_ebadf(self.0.read_buf_exact(buf), || Err(io::Error::READ_EXACT_EOF)) +// } + +// fn read_to_end(&mut self, buf: &mut Vec) -> io::Result { +// handle_ebadf(self.0.read_to_end(buf), || Ok(0)) +// } + +// fn read_to_string(&mut self, buf: &mut String) -> io::Result { +// handle_ebadf(self.0.read_to_string(buf), || Ok(0)) +// } +// } + +// impl Write for StdoutRaw { +// fn write(&mut self, buf: &[u8]) -> io::Result { +// handle_ebadf(self.0.write(buf), || Ok(buf.len())) +// } + +// fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { +// let total = || Ok(bufs.iter().map(|b| b.len()).sum()); +// handle_ebadf(self.0.write_vectored(bufs), total) +// } + +// #[inline] +// fn is_write_vectored(&self) -> bool { +// self.0.is_write_vectored() +// } + +// fn flush(&mut self) -> io::Result<()> { +// handle_ebadf(self.0.flush(), || Ok(())) +// } + +// fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { +// handle_ebadf(self.0.write_all(buf), || Ok(())) +// } + +// fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> { +// handle_ebadf(self.0.write_all_vectored(bufs), || Ok(())) +// } + +// fn write_fmt(&mut self, fmt: fmt::Arguments<'_>) -> io::Result<()> { +// handle_ebadf(self.0.write_fmt(fmt), || Ok(())) +// } +// } + +// impl Write for StderrRaw { +// fn write(&mut self, buf: &[u8]) -> io::Result { +// handle_ebadf(self.0.write(buf), || Ok(buf.len())) +// } + +// fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { +// let total = || Ok(bufs.iter().map(|b| b.len()).sum()); +// handle_ebadf(self.0.write_vectored(bufs), total) +// } + +// #[inline] +// fn is_write_vectored(&self) -> bool { +// self.0.is_write_vectored() +// } + +// fn flush(&mut self) -> io::Result<()> { +// handle_ebadf(self.0.flush(), || Ok(())) +// } + +// fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { +// handle_ebadf(self.0.write_all(buf), || Ok(())) +// } + +// fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> { +// handle_ebadf(self.0.write_all_vectored(bufs), || Ok(())) +// } + +// fn write_fmt(&mut self, fmt: fmt::Arguments<'_>) -> io::Result<()> { +// handle_ebadf(self.0.write_fmt(fmt), || Ok(())) +// } +// } + +// fn handle_ebadf(r: io::Result, default: impl FnOnce() -> io::Result) -> io::Result { +// match r { +// Err(ref e) if stdio::is_ebadf(e) => default(), +// r => r, +// } +// } + +// /// A handle to the standard input stream of a process. +// /// +// /// Each handle is a shared reference to a global buffer of input data to this +// /// process. A handle can be `lock`'d to gain full access to [`BufRead`] methods +// /// (e.g., `.lines()`). Reads to this handle are otherwise locked with respect +// /// to other reads. +// /// +// /// This handle implements the `Read` trait, but beware that concurrent reads +// /// of `Stdin` must be executed with care. +// /// +// /// Created by the [`io::stdin`] method. +// /// +// /// [`io::stdin`]: stdin +// /// +// /// ### Note: Windows Portability Considerations +// /// +// /// When operating in a console, the Windows implementation of this stream does not support +// /// non-UTF-8 byte sequences. Attempting to read bytes that are not valid UTF-8 will return +// /// an error. +// /// +// /// In a process with a detached console, such as one using +// /// `#![windows_subsystem = "windows"]`, or in a child process spawned from such a process, +// /// the contained handle will be null. In such cases, the standard library's `Read` and +// /// `Write` will do nothing and silently succeed. All other I/O operations, via the +// /// standard library or via raw Windows API calls, will fail. +// /// +// /// # Examples +// /// +// /// ```no_run +// /// use std::io; +// /// +// /// fn main() -> io::Result<()> { +// /// let mut buffer = String::new(); +// /// let stdin = io::stdin(); // We get `Stdin` here. +// /// stdin.read_line(&mut buffer)?; +// /// Ok(()) +// /// } +// /// ``` +// #[stable(feature = "rust1", since = "1.0.0")] +// #[cfg_attr(not(test), rustc_diagnostic_item = "Stdin")] +// pub struct Stdin { +// inner: &'static Mutex>, +// } + +// /// A locked reference to the [`Stdin`] handle. +// /// +// /// This handle implements both the [`Read`] and [`BufRead`] traits, and +// /// is constructed via the [`Stdin::lock`] method. +// /// +// /// ### Note: Windows Portability Considerations +// /// +// /// When operating in a console, the Windows implementation of this stream does not support +// /// non-UTF-8 byte sequences. Attempting to read bytes that are not valid UTF-8 will return +// /// an error. +// /// +// /// In a process with a detached console, such as one using +// /// `#![windows_subsystem = "windows"]`, or in a child process spawned from such a process, +// /// the contained handle will be null. In such cases, the standard library's `Read` and +// /// `Write` will do nothing and silently succeed. All other I/O operations, via the +// /// standard library or via raw Windows API calls, will fail. +// /// +// /// # Examples +// /// +// /// ```no_run +// /// use std::io::{self, BufRead}; +// /// +// /// fn main() -> io::Result<()> { +// /// let mut buffer = String::new(); +// /// let stdin = io::stdin(); // We get `Stdin` here. +// /// { +// /// let mut handle = stdin.lock(); // We get `StdinLock` here. +// /// handle.read_line(&mut buffer)?; +// /// } // `StdinLock` is dropped here. +// /// Ok(()) +// /// } +// /// ``` +// #[must_use = "if unused stdin will immediately unlock"] +// #[stable(feature = "rust1", since = "1.0.0")] +// pub struct StdinLock<'a> { +// inner: MutexGuard<'a, BufReader>, +// } + +// /// Constructs a new handle to the standard input of the current process. +// /// +// /// Each handle returned is a reference to a shared global buffer whose access +// /// is synchronized via a mutex. If you need more explicit control over +// /// locking, see the [`Stdin::lock`] method. +// /// +// /// ### Note: Windows Portability Considerations +// /// +// /// When operating in a console, the Windows implementation of this stream does not support +// /// non-UTF-8 byte sequences. Attempting to read bytes that are not valid UTF-8 will return +// /// an error. +// /// +// /// In a process with a detached console, such as one using +// /// `#![windows_subsystem = "windows"]`, or in a child process spawned from such a process, +// /// the contained handle will be null. In such cases, the standard library's `Read` and +// /// `Write` will do nothing and silently succeed. All other I/O operations, via the +// /// standard library or via raw Windows API calls, will fail. +// /// +// /// # Examples +// /// +// /// Using implicit synchronization: +// /// +// /// ```no_run +// /// use std::io; +// /// +// /// fn main() -> io::Result<()> { +// /// let mut buffer = String::new(); +// /// io::stdin().read_line(&mut buffer)?; +// /// Ok(()) +// /// } +// /// ``` +// /// +// /// Using explicit synchronization: +// /// +// /// ```no_run +// /// use std::io::{self, BufRead}; +// /// +// /// fn main() -> io::Result<()> { +// /// let mut buffer = String::new(); +// /// let stdin = io::stdin(); +// /// let mut handle = stdin.lock(); +// /// +// /// handle.read_line(&mut buffer)?; +// /// Ok(()) +// /// } +// /// ``` +// #[must_use] +// #[stable(feature = "rust1", since = "1.0.0")] +// pub fn stdin() -> Stdin { +// static INSTANCE: OnceLock>> = OnceLock::new(); +// Stdin { +// inner: INSTANCE.get_or_init(|| { +// Mutex::new(BufReader::with_capacity(stdio::STDIN_BUF_SIZE, stdin_raw())) +// }), +// } +// } + +// impl Stdin { +// /// Locks this handle to the standard input stream, returning a readable +// /// guard. +// /// +// /// The lock is released when the returned lock goes out of scope. The +// /// returned guard also implements the [`Read`] and [`BufRead`] traits for +// /// accessing the underlying data. +// /// +// /// # Examples +// /// +// /// ```no_run +// /// use std::io::{self, BufRead}; +// /// +// /// fn main() -> io::Result<()> { +// /// let mut buffer = String::new(); +// /// let stdin = io::stdin(); +// /// let mut handle = stdin.lock(); +// /// +// /// handle.read_line(&mut buffer)?; +// /// Ok(()) +// /// } +// /// ``` +// #[stable(feature = "rust1", since = "1.0.0")] +// pub fn lock(&self) -> StdinLock<'static> { +// // Locks this handle with 'static lifetime. This depends on the +// // implementation detail that the underlying `Mutex` is static. +// StdinLock { inner: self.inner.lock().unwrap_or_else(|e| e.into_inner()) } +// } + +// /// Locks this handle and reads a line of input, appending it to the specified buffer. +// /// +// /// For detailed semantics of this method, see the documentation on +// /// [`BufRead::read_line`]. In particular: +// /// * Previous content of the buffer will be preserved. To avoid appending +// /// to the buffer, you need to [`clear`] it first. +// /// * The trailing newline character, if any, is included in the buffer. +// /// +// /// [`clear`]: String::clear +// /// +// /// # Examples +// /// +// /// ```no_run +// /// use std::io; +// /// +// /// let mut input = String::new(); +// /// match io::stdin().read_line(&mut input) { +// /// Ok(n) => { +// /// println!("{n} bytes read"); +// /// println!("{input}"); +// /// } +// /// Err(error) => println!("error: {error}"), +// /// } +// /// ``` +// /// +// /// You can run the example one of two ways: +// /// +// /// - Pipe some text to it, e.g., `printf foo | path/to/executable` +// /// - Give it text interactively by running the executable directly, +// /// in which case it will wait for the Enter key to be pressed before +// /// continuing +// #[stable(feature = "rust1", since = "1.0.0")] +// #[rustc_confusables("get_line")] +// pub fn read_line(&self, buf: &mut String) -> io::Result { +// self.lock().read_line(buf) +// } + +// /// Consumes this handle and returns an iterator over input lines. +// /// +// /// For detailed semantics of this method, see the documentation on +// /// [`BufRead::lines`]. +// /// +// /// # Examples +// /// +// /// ```no_run +// /// use std::io; +// /// +// /// let lines = io::stdin().lines(); +// /// for line in lines { +// /// println!("got a line: {}", line.unwrap()); +// /// } +// /// ``` +// #[must_use = "`self` will be dropped if the result is not used"] +// #[stable(feature = "stdin_forwarders", since = "1.62.0")] +// pub fn lines(self) -> Lines> { +// self.lock().lines() +// } +// } + +// #[stable(feature = "std_debug", since = "1.16.0")] +// impl fmt::Debug for Stdin { +// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { +// f.debug_struct("Stdin").finish_non_exhaustive() +// } +// } + +// #[stable(feature = "rust1", since = "1.0.0")] +// impl Read for Stdin { +// fn read(&mut self, buf: &mut [u8]) -> io::Result { +// self.lock().read(buf) +// } +// fn read_buf(&mut self, buf: BorrowedCursor<'_>) -> io::Result<()> { +// self.lock().read_buf(buf) +// } +// fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { +// self.lock().read_vectored(bufs) +// } +// #[inline] +// fn is_read_vectored(&self) -> bool { +// self.lock().is_read_vectored() +// } +// fn read_to_end(&mut self, buf: &mut Vec) -> io::Result { +// self.lock().read_to_end(buf) +// } +// fn read_to_string(&mut self, buf: &mut String) -> io::Result { +// self.lock().read_to_string(buf) +// } +// fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> { +// self.lock().read_exact(buf) +// } +// fn read_buf_exact(&mut self, cursor: BorrowedCursor<'_>) -> io::Result<()> { +// self.lock().read_buf_exact(cursor) +// } +// } + +// #[stable(feature = "read_shared_stdin", since = "1.78.0")] +// impl Read for &Stdin { +// fn read(&mut self, buf: &mut [u8]) -> io::Result { +// self.lock().read(buf) +// } +// fn read_buf(&mut self, buf: BorrowedCursor<'_>) -> io::Result<()> { +// self.lock().read_buf(buf) +// } +// fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { +// self.lock().read_vectored(bufs) +// } +// #[inline] +// fn is_read_vectored(&self) -> bool { +// self.lock().is_read_vectored() +// } +// fn read_to_end(&mut self, buf: &mut Vec) -> io::Result { +// self.lock().read_to_end(buf) +// } +// fn read_to_string(&mut self, buf: &mut String) -> io::Result { +// self.lock().read_to_string(buf) +// } +// fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> { +// self.lock().read_exact(buf) +// } +// fn read_buf_exact(&mut self, cursor: BorrowedCursor<'_>) -> io::Result<()> { +// self.lock().read_buf_exact(cursor) +// } +// } + +// // only used by platform-dependent io::copy specializations, i.e. unused on some platforms +// #[cfg(any(target_os = "linux", target_os = "android"))] +// impl StdinLock<'_> { +// pub(crate) fn as_mut_buf(&mut self) -> &mut BufReader { +// &mut self.inner +// } +// } + +// #[stable(feature = "rust1", since = "1.0.0")] +// impl Read for StdinLock<'_> { +// fn read(&mut self, buf: &mut [u8]) -> io::Result { +// self.inner.read(buf) +// } + +// fn read_buf(&mut self, buf: BorrowedCursor<'_>) -> io::Result<()> { +// self.inner.read_buf(buf) +// } + +// fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { +// self.inner.read_vectored(bufs) +// } + +// #[inline] +// fn is_read_vectored(&self) -> bool { +// self.inner.is_read_vectored() +// } + +// fn read_to_end(&mut self, buf: &mut Vec) -> io::Result { +// self.inner.read_to_end(buf) +// } + +// fn read_to_string(&mut self, buf: &mut String) -> io::Result { +// self.inner.read_to_string(buf) +// } + +// fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> { +// self.inner.read_exact(buf) +// } + +// fn read_buf_exact(&mut self, cursor: BorrowedCursor<'_>) -> io::Result<()> { +// self.inner.read_buf_exact(cursor) +// } +// } + +// impl SpecReadByte for StdinLock<'_> { +// #[inline] +// fn spec_read_byte(&mut self) -> Option> { +// BufReader::spec_read_byte(&mut *self.inner) +// } +// } + +// #[stable(feature = "rust1", since = "1.0.0")] +// impl BufRead for StdinLock<'_> { +// fn fill_buf(&mut self) -> io::Result<&[u8]> { +// self.inner.fill_buf() +// } + +// fn consume(&mut self, n: usize) { +// self.inner.consume(n) +// } + +// fn read_until(&mut self, byte: u8, buf: &mut Vec) -> io::Result { +// self.inner.read_until(byte, buf) +// } + +// fn read_line(&mut self, buf: &mut String) -> io::Result { +// self.inner.read_line(buf) +// } +// } + +// #[stable(feature = "std_debug", since = "1.16.0")] +// impl fmt::Debug for StdinLock<'_> { +// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { +// f.debug_struct("StdinLock").finish_non_exhaustive() +// } +// } + +// /// A handle to the global standard output stream of the current process. +// /// +// /// Each handle shares a global buffer of data to be written to the standard +// /// output stream. Access is also synchronized via a lock and explicit control +// /// over locking is available via the [`lock`] method. +// /// +// /// By default, the handle is line-buffered when connected to a terminal, meaning +// /// it flushes automatically when a newline (`\n`) is encountered. For immediate +// /// output, you can manually call the [`flush`] method. When the handle goes out +// /// of scope, the buffer is automatically flushed. +// /// +// /// Created by the [`io::stdout`] method. +// /// +// /// ### Note: Windows Portability Considerations +// /// +// /// When operating in a console, the Windows implementation of this stream does not support +// /// non-UTF-8 byte sequences. Attempting to write bytes that are not valid UTF-8 will return +// /// an error. +// /// +// /// In a process with a detached console, such as one using +// /// `#![windows_subsystem = "windows"]`, or in a child process spawned from such a process, +// /// the contained handle will be null. In such cases, the standard library's `Read` and +// /// `Write` will do nothing and silently succeed. All other I/O operations, via the +// /// standard library or via raw Windows API calls, will fail. +// /// +// /// [`lock`]: Stdout::lock +// /// [`flush`]: Write::flush +// /// [`io::stdout`]: stdout +// #[stable(feature = "rust1", since = "1.0.0")] +// pub struct Stdout { +// // FIXME: this should be LineWriter or BufWriter depending on the state of +// // stdout (tty or not). Note that if this is not line buffered it +// // should also flush-on-panic or some form of flush-on-abort. +// inner: &'static ReentrantLock>>, +// } + +// /// A locked reference to the [`Stdout`] handle. +// /// +// /// This handle implements the [`Write`] trait, and is constructed via +// /// the [`Stdout::lock`] method. See its documentation for more. +// /// +// /// By default, the handle is line-buffered when connected to a terminal, meaning +// /// it flushes automatically when a newline (`\n`) is encountered. For immediate +// /// output, you can manually call the [`flush`] method. When the handle goes out +// /// of scope, the buffer is automatically flushed. +// /// +// /// ### Note: Windows Portability Considerations +// /// +// /// When operating in a console, the Windows implementation of this stream does not support +// /// non-UTF-8 byte sequences. Attempting to write bytes that are not valid UTF-8 will return +// /// an error. +// /// +// /// In a process with a detached console, such as one using +// /// `#![windows_subsystem = "windows"]`, or in a child process spawned from such a process, +// /// the contained handle will be null. In such cases, the standard library's `Read` and +// /// `Write` will do nothing and silently succeed. All other I/O operations, via the +// /// standard library or via raw Windows API calls, will fail. +// /// +// /// [`flush`]: Write::flush +// #[must_use = "if unused stdout will immediately unlock"] +// #[stable(feature = "rust1", since = "1.0.0")] +// pub struct StdoutLock<'a> { +// inner: ReentrantLockGuard<'a, RefCell>>, +// } + +// static STDOUT: OnceLock>>> = OnceLock::new(); + +// /// Constructs a new handle to the standard output of the current process. +// /// +// /// Each handle returned is a reference to a shared global buffer whose access +// /// is synchronized via a mutex. If you need more explicit control over +// /// locking, see the [`Stdout::lock`] method. +// /// +// /// By default, the handle is line-buffered when connected to a terminal, meaning +// /// it flushes automatically when a newline (`\n`) is encountered. For immediate +// /// output, you can manually call the [`flush`] method. When the handle goes out +// /// of scope, the buffer is automatically flushed. +// /// +// /// ### Note: Windows Portability Considerations +// /// +// /// When operating in a console, the Windows implementation of this stream does not support +// /// non-UTF-8 byte sequences. Attempting to write bytes that are not valid UTF-8 will return +// /// an error. +// /// +// /// In a process with a detached console, such as one using +// /// `#![windows_subsystem = "windows"]`, or in a child process spawned from such a process, +// /// the contained handle will be null. In such cases, the standard library's `Read` and +// /// `Write` will do nothing and silently succeed. All other I/O operations, via the +// /// standard library or via raw Windows API calls, will fail. +// /// +// /// # Examples +// /// +// /// Using implicit synchronization: +// /// +// /// ```no_run +// /// use std::io::{self, Write}; +// /// +// /// fn main() -> io::Result<()> { +// /// io::stdout().write_all(b"hello world")?; +// /// +// /// Ok(()) +// /// } +// /// ``` +// /// +// /// Using explicit synchronization: +// /// +// /// ```no_run +// /// use std::io::{self, Write}; +// /// +// /// fn main() -> io::Result<()> { +// /// let stdout = io::stdout(); +// /// let mut handle = stdout.lock(); +// /// +// /// handle.write_all(b"hello world")?; +// /// +// /// Ok(()) +// /// } +// /// ``` +// /// +// /// Ensuring output is flushed immediately: +// /// +// /// ```no_run +// /// use std::io::{self, Write}; +// /// +// /// fn main() -> io::Result<()> { +// /// let mut stdout = io::stdout(); +// /// stdout.write_all(b"hello, ")?; +// /// stdout.flush()?; // Manual flush +// /// stdout.write_all(b"world!\n")?; // Automatically flushed +// /// Ok(()) +// /// } +// /// ``` +// /// +// /// [`flush`]: Write::flush +// #[must_use] +// #[stable(feature = "rust1", since = "1.0.0")] +// #[cfg_attr(not(test), rustc_diagnostic_item = "io_stdout")] +// pub fn stdout() -> Stdout { +// Stdout { +// inner: STDOUT +// .get_or_init(|| ReentrantLock::new(RefCell::new(LineWriter::new(stdout_raw())))), +// } +// } + +// // Flush the data and disable buffering during shutdown +// // by replacing the line writer by one with zero +// // buffering capacity. +// pub fn cleanup() { +// let mut initialized = false; +// let stdout = STDOUT.get_or_init(|| { +// initialized = true; +// ReentrantLock::new(RefCell::new(LineWriter::with_capacity(0, stdout_raw()))) +// }); + +// if !initialized { +// // The buffer was previously initialized, overwrite it here. +// // We use try_lock() instead of lock(), because someone +// // might have leaked a StdoutLock, which would +// // otherwise cause a deadlock here. +// if let Some(lock) = stdout.try_lock() { +// *lock.borrow_mut() = LineWriter::with_capacity(0, stdout_raw()); +// } +// } +// } + +// impl Stdout { +// /// Locks this handle to the standard output stream, returning a writable +// /// guard. +// /// +// /// The lock is released when the returned lock goes out of scope. The +// /// returned guard also implements the `Write` trait for writing data. +// /// +// /// # Examples +// /// +// /// ```no_run +// /// use std::io::{self, Write}; +// /// +// /// fn main() -> io::Result<()> { +// /// let mut stdout = io::stdout().lock(); +// /// +// /// stdout.write_all(b"hello world")?; +// /// +// /// Ok(()) +// /// } +// /// ``` +// #[stable(feature = "rust1", since = "1.0.0")] +// pub fn lock(&self) -> StdoutLock<'static> { +// // Locks this handle with 'static lifetime. This depends on the +// // implementation detail that the underlying `ReentrantMutex` is +// // static. +// StdoutLock { inner: self.inner.lock() } +// } +// } + +// #[stable(feature = "catch_unwind", since = "1.9.0")] +// impl UnwindSafe for Stdout {} + +// #[stable(feature = "catch_unwind", since = "1.9.0")] +// impl RefUnwindSafe for Stdout {} + +// #[stable(feature = "std_debug", since = "1.16.0")] +// impl fmt::Debug for Stdout { +// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { +// f.debug_struct("Stdout").finish_non_exhaustive() +// } +// } + +// #[stable(feature = "rust1", since = "1.0.0")] +// impl Write for Stdout { +// fn write(&mut self, buf: &[u8]) -> io::Result { +// (&*self).write(buf) +// } +// fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { +// (&*self).write_vectored(bufs) +// } +// #[inline] +// fn is_write_vectored(&self) -> bool { +// io::Write::is_write_vectored(&&*self) +// } +// fn flush(&mut self) -> io::Result<()> { +// (&*self).flush() +// } +// fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { +// (&*self).write_all(buf) +// } +// fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> { +// (&*self).write_all_vectored(bufs) +// } +// fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> io::Result<()> { +// (&*self).write_fmt(args) +// } +// } + +// #[stable(feature = "write_mt", since = "1.48.0")] +// impl Write for &Stdout { +// fn write(&mut self, buf: &[u8]) -> io::Result { +// self.lock().write(buf) +// } +// fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { +// self.lock().write_vectored(bufs) +// } +// #[inline] +// fn is_write_vectored(&self) -> bool { +// self.lock().is_write_vectored() +// } +// fn flush(&mut self) -> io::Result<()> { +// self.lock().flush() +// } +// fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { +// self.lock().write_all(buf) +// } +// fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> { +// self.lock().write_all_vectored(bufs) +// } +// fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> io::Result<()> { +// self.lock().write_fmt(args) +// } +// } + +// #[stable(feature = "catch_unwind", since = "1.9.0")] +// impl UnwindSafe for StdoutLock<'_> {} + +// #[stable(feature = "catch_unwind", since = "1.9.0")] +// impl RefUnwindSafe for StdoutLock<'_> {} + +// #[stable(feature = "rust1", since = "1.0.0")] +// impl Write for StdoutLock<'_> { +// fn write(&mut self, buf: &[u8]) -> io::Result { +// self.inner.borrow_mut().write(buf) +// } +// fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { +// self.inner.borrow_mut().write_vectored(bufs) +// } +// #[inline] +// fn is_write_vectored(&self) -> bool { +// self.inner.borrow_mut().is_write_vectored() +// } +// fn flush(&mut self) -> io::Result<()> { +// self.inner.borrow_mut().flush() +// } +// fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { +// self.inner.borrow_mut().write_all(buf) +// } +// fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> { +// self.inner.borrow_mut().write_all_vectored(bufs) +// } +// } + +// #[stable(feature = "std_debug", since = "1.16.0")] +// impl fmt::Debug for StdoutLock<'_> { +// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { +// f.debug_struct("StdoutLock").finish_non_exhaustive() +// } +// } + +// /// A handle to the standard error stream of a process. +// /// +// /// For more information, see the [`io::stderr`] method. +// /// +// /// [`io::stderr`]: stderr +// /// +// /// ### Note: Windows Portability Considerations +// /// +// /// When operating in a console, the Windows implementation of this stream does not support +// /// non-UTF-8 byte sequences. Attempting to write bytes that are not valid UTF-8 will return +// /// an error. +// /// +// /// In a process with a detached console, such as one using +// /// `#![windows_subsystem = "windows"]`, or in a child process spawned from such a process, +// /// the contained handle will be null. In such cases, the standard library's `Read` and +// /// `Write` will do nothing and silently succeed. All other I/O operations, via the +// /// standard library or via raw Windows API calls, will fail. +// #[stable(feature = "rust1", since = "1.0.0")] +// pub struct Stderr { +// inner: &'static ReentrantLock>, +// } + +// /// A locked reference to the [`Stderr`] handle. +// /// +// /// This handle implements the [`Write`] trait and is constructed via +// /// the [`Stderr::lock`] method. See its documentation for more. +// /// +// /// ### Note: Windows Portability Considerations +// /// +// /// When operating in a console, the Windows implementation of this stream does not support +// /// non-UTF-8 byte sequences. Attempting to write bytes that are not valid UTF-8 will return +// /// an error. +// /// +// /// In a process with a detached console, such as one using +// /// `#![windows_subsystem = "windows"]`, or in a child process spawned from such a process, +// /// the contained handle will be null. In such cases, the standard library's `Read` and +// /// `Write` will do nothing and silently succeed. All other I/O operations, via the +// /// standard library or via raw Windows API calls, will fail. +// #[must_use = "if unused stderr will immediately unlock"] +// #[stable(feature = "rust1", since = "1.0.0")] +// pub struct StderrLock<'a> { +// inner: ReentrantLockGuard<'a, RefCell>, +// } + +// /// Constructs a new handle to the standard error of the current process. +// /// +// /// This handle is not buffered. +// /// +// /// ### Note: Windows Portability Considerations +// /// +// /// When operating in a console, the Windows implementation of this stream does not support +// /// non-UTF-8 byte sequences. Attempting to write bytes that are not valid UTF-8 will return +// /// an error. +// /// +// /// In a process with a detached console, such as one using +// /// `#![windows_subsystem = "windows"]`, or in a child process spawned from such a process, +// /// the contained handle will be null. In such cases, the standard library's `Read` and +// /// `Write` will do nothing and silently succeed. All other I/O operations, via the +// /// standard library or via raw Windows API calls, will fail. +// /// +// /// # Examples +// /// +// /// Using implicit synchronization: +// /// +// /// ```no_run +// /// use std::io::{self, Write}; +// /// +// /// fn main() -> io::Result<()> { +// /// io::stderr().write_all(b"hello world")?; +// /// +// /// Ok(()) +// /// } +// /// ``` +// /// +// /// Using explicit synchronization: +// /// +// /// ```no_run +// /// use std::io::{self, Write}; +// /// +// /// fn main() -> io::Result<()> { +// /// let stderr = io::stderr(); +// /// let mut handle = stderr.lock(); +// /// +// /// handle.write_all(b"hello world")?; +// /// +// /// Ok(()) +// /// } +// /// ``` +// #[must_use] +// #[stable(feature = "rust1", since = "1.0.0")] +// #[cfg_attr(not(test), rustc_diagnostic_item = "io_stderr")] +// pub fn stderr() -> Stderr { +// // Note that unlike `stdout()` we don't use `at_exit` here to register a +// // destructor. Stderr is not buffered, so there's no need to run a +// // destructor for flushing the buffer +// static INSTANCE: ReentrantLock> = +// ReentrantLock::new(RefCell::new(stderr_raw())); + +// Stderr { inner: &INSTANCE } +// } + +// impl Stderr { +// /// Locks this handle to the standard error stream, returning a writable +// /// guard. +// /// +// /// The lock is released when the returned lock goes out of scope. The +// /// returned guard also implements the [`Write`] trait for writing data. +// /// +// /// # Examples +// /// +// /// ``` +// /// use std::io::{self, Write}; +// /// +// /// fn foo() -> io::Result<()> { +// /// let stderr = io::stderr(); +// /// let mut handle = stderr.lock(); +// /// +// /// handle.write_all(b"hello world")?; +// /// +// /// Ok(()) +// /// } +// /// ``` +// #[stable(feature = "rust1", since = "1.0.0")] +// pub fn lock(&self) -> StderrLock<'static> { +// // Locks this handle with 'static lifetime. This depends on the +// // implementation detail that the underlying `ReentrantMutex` is +// // static. +// StderrLock { inner: self.inner.lock() } +// } +// } + +// #[stable(feature = "catch_unwind", since = "1.9.0")] +// impl UnwindSafe for Stderr {} + +// #[stable(feature = "catch_unwind", since = "1.9.0")] +// impl RefUnwindSafe for Stderr {} + +// #[stable(feature = "std_debug", since = "1.16.0")] +// impl fmt::Debug for Stderr { +// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { +// f.debug_struct("Stderr").finish_non_exhaustive() +// } +// } + +// #[stable(feature = "rust1", since = "1.0.0")] +// impl Write for Stderr { +// fn write(&mut self, buf: &[u8]) -> io::Result { +// (&*self).write(buf) +// } +// fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { +// (&*self).write_vectored(bufs) +// } +// #[inline] +// fn is_write_vectored(&self) -> bool { +// io::Write::is_write_vectored(&&*self) +// } +// fn flush(&mut self) -> io::Result<()> { +// (&*self).flush() +// } +// fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { +// (&*self).write_all(buf) +// } +// fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> { +// (&*self).write_all_vectored(bufs) +// } +// fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> io::Result<()> { +// (&*self).write_fmt(args) +// } +// } + +// #[stable(feature = "write_mt", since = "1.48.0")] +// impl Write for &Stderr { +// fn write(&mut self, buf: &[u8]) -> io::Result { +// self.lock().write(buf) +// } +// fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { +// self.lock().write_vectored(bufs) +// } +// #[inline] +// fn is_write_vectored(&self) -> bool { +// self.lock().is_write_vectored() +// } +// fn flush(&mut self) -> io::Result<()> { +// self.lock().flush() +// } +// fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { +// self.lock().write_all(buf) +// } +// fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> { +// self.lock().write_all_vectored(bufs) +// } +// fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> io::Result<()> { +// self.lock().write_fmt(args) +// } +// } + +// #[stable(feature = "catch_unwind", since = "1.9.0")] +// impl UnwindSafe for StderrLock<'_> {} + +// #[stable(feature = "catch_unwind", since = "1.9.0")] +// impl RefUnwindSafe for StderrLock<'_> {} + +// #[stable(feature = "rust1", since = "1.0.0")] +// impl Write for StderrLock<'_> { +// fn write(&mut self, buf: &[u8]) -> io::Result { +// self.inner.borrow_mut().write(buf) +// } +// fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { +// self.inner.borrow_mut().write_vectored(bufs) +// } +// #[inline] +// fn is_write_vectored(&self) -> bool { +// self.inner.borrow_mut().is_write_vectored() +// } +// fn flush(&mut self) -> io::Result<()> { +// self.inner.borrow_mut().flush() +// } +// fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { +// self.inner.borrow_mut().write_all(buf) +// } +// fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> { +// self.inner.borrow_mut().write_all_vectored(bufs) +// } +// } + +// #[stable(feature = "std_debug", since = "1.16.0")] +// impl fmt::Debug for StderrLock<'_> { +// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { +// f.debug_struct("StderrLock").finish_non_exhaustive() +// } +// } + +// /// Sets the thread-local output capture buffer and returns the old one. +// #[unstable( +// feature = "internal_output_capture", +// reason = "this function is meant for use in the test crate \ +// and may disappear in the future", +// issue = "none" +// )] +// #[doc(hidden)] +// pub fn set_output_capture(sink: Option) -> Option { +// try_set_output_capture(sink).expect( +// "cannot access a Thread Local Storage value \ +// during or after destruction", +// ) +// } /// Tries to set the thread-local output capture buffer and returns the old one. /// This may fail once thread-local destructors are called. It's used in panic @@ -1131,160 +1131,162 @@ pub fn set_output_capture(sink: Option) -> Option { pub fn try_set_output_capture( sink: Option, ) -> Result, AccessError> { - if sink.is_none() && !OUTPUT_CAPTURE_USED.load(Ordering::Relaxed) { - // OUTPUT_CAPTURE is definitely None since OUTPUT_CAPTURE_USED is false. - return Ok(None); - } - OUTPUT_CAPTURE_USED.store(true, Ordering::Relaxed); - OUTPUT_CAPTURE.try_with(move |slot| slot.replace(sink)) + Ok(None) + //todo!() + // if sink.is_none() && !OUTPUT_CAPTURE_USED.load(Ordering::Relaxed) { + // // OUTPUT_CAPTURE is definitely None since OUTPUT_CAPTURE_USED is false. + // return Ok(None); + // } + // OUTPUT_CAPTURE_USED.store(true, Ordering::Relaxed); + // OUTPUT_CAPTURE.try_with(move |slot| slot.replace(sink)) } -/// Writes `args` to the capture buffer if enabled and possible, or `global_s` -/// otherwise. `label` identifies the stream in a panic message. -/// -/// This function is used to print error messages, so it takes extra -/// care to avoid causing a panic when `OUTPUT_CAPTURE` is unusable. -/// For instance, if the TLS key for output capturing is already destroyed, or -/// if the local stream is in use by another thread, it will just fall back to -/// the global stream. -/// -/// However, if the actual I/O causes an error, this function does panic. -/// -/// Writing to non-blocking stdout/stderr can cause an error, which will lead -/// this function to panic. -fn print_to(args: fmt::Arguments<'_>, global_s: fn() -> T, label: &str) -where - T: Write, -{ - if print_to_buffer_if_capture_used(args) { - // Successfully wrote to capture buffer. - return; - } +// /// Writes `args` to the capture buffer if enabled and possible, or `global_s` +// /// otherwise. `label` identifies the stream in a panic message. +// /// +// /// This function is used to print error messages, so it takes extra +// /// care to avoid causing a panic when `OUTPUT_CAPTURE` is unusable. +// /// For instance, if the TLS key for output capturing is already destroyed, or +// /// if the local stream is in use by another thread, it will just fall back to +// /// the global stream. +// /// +// /// However, if the actual I/O causes an error, this function does panic. +// /// +// /// Writing to non-blocking stdout/stderr can cause an error, which will lead +// /// this function to panic. +// fn print_to(args: fmt::Arguments<'_>, global_s: fn() -> T, label: &str) +// where +// T: Write, +// { +// if print_to_buffer_if_capture_used(args) { +// // Successfully wrote to capture buffer. +// return; +// } - if let Err(e) = global_s().write_fmt(args) { - panic!("failed printing to {label}: {e}"); - } -} +// if let Err(e) = global_s().write_fmt(args) { +// panic!("failed printing to {label}: {e}"); +// } +// } -fn print_to_buffer_if_capture_used(args: fmt::Arguments<'_>) -> bool { - OUTPUT_CAPTURE_USED.load(Ordering::Relaxed) - && OUTPUT_CAPTURE.try_with(|s| { - // Note that we completely remove a local sink to write to in case - // our printing recursively panics/prints, so the recursive - // panic/print goes to the global sink instead of our local sink. - s.take().map(|w| { - let _ = w.lock().unwrap_or_else(|e| e.into_inner()).write_fmt(args); - s.set(Some(w)); - }) - }) == Ok(Some(())) -} +// fn print_to_buffer_if_capture_used(args: fmt::Arguments<'_>) -> bool { +// OUTPUT_CAPTURE_USED.load(Ordering::Relaxed) +// && OUTPUT_CAPTURE.try_with(|s| { +// // Note that we completely remove a local sink to write to in case +// // our printing recursively panics/prints, so the recursive +// // panic/print goes to the global sink instead of our local sink. +// s.take().map(|w| { +// let _ = w.lock().unwrap_or_else(|e| e.into_inner()).write_fmt(args); +// s.set(Some(w)); +// }) +// }) == Ok(Some(())) +// } -/// Used by impl Termination for Result to print error after `main` or a test -/// has returned. Should avoid panicking, although we can't help it if one of -/// the Display impls inside args decides to. -pub(crate) fn attempt_print_to_stderr(args: fmt::Arguments<'_>) { - if print_to_buffer_if_capture_used(args) { - return; - } +// /// Used by impl Termination for Result to print error after `main` or a test +// /// has returned. Should avoid panicking, although we can't help it if one of +// /// the Display impls inside args decides to. +// pub(crate) fn attempt_print_to_stderr(args: fmt::Arguments<'_>) { +// if print_to_buffer_if_capture_used(args) { +// return; +// } - // Ignore error if the write fails, for example because stderr is already - // closed. There is not much point panicking at this point. - let _ = stderr().write_fmt(args); -} +// // Ignore error if the write fails, for example because stderr is already +// // closed. There is not much point panicking at this point. +// let _ = stderr().write_fmt(args); +// } -/// Trait to determine if a descriptor/handle refers to a terminal/tty. -#[stable(feature = "is_terminal", since = "1.70.0")] -pub trait IsTerminal: crate::sealed::Sealed { - /// Returns `true` if the descriptor/handle refers to a terminal/tty. - /// - /// On platforms where Rust does not know how to detect a terminal yet, this will return - /// `false`. This will also return `false` if an unexpected error occurred, such as from - /// passing an invalid file descriptor. - /// - /// # Platform-specific behavior - /// - /// On Windows, in addition to detecting consoles, this currently uses some heuristics to - /// detect older msys/cygwin/mingw pseudo-terminals based on device name: devices with names - /// starting with `msys-` or `cygwin-` and ending in `-pty` will be considered terminals. - /// Note that this [may change in the future][changes]. - /// - /// # Examples - /// - /// An example of a type for which `IsTerminal` is implemented is [`Stdin`]: - /// - /// ```no_run - /// use std::io::{self, IsTerminal, Write}; - /// - /// fn main() -> io::Result<()> { - /// let stdin = io::stdin(); - /// - /// // Indicate that the user is prompted for input, if this is a terminal. - /// if stdin.is_terminal() { - /// print!("> "); - /// io::stdout().flush()?; - /// } - /// - /// let mut name = String::new(); - /// let _ = stdin.read_line(&mut name)?; - /// - /// println!("Hello {}", name.trim_end()); - /// - /// Ok(()) - /// } - /// ``` - /// - /// The example can be run in two ways: - /// - /// - If you run this example by piping some text to it, e.g. `echo "foo" | path/to/executable` - /// it will print: `Hello foo`. - /// - If you instead run the example interactively by running `path/to/executable` directly, it will - /// prompt for input. - /// - /// [changes]: io#platform-specific-behavior - /// [`Stdin`]: crate::io::Stdin - #[doc(alias = "isatty")] - #[stable(feature = "is_terminal", since = "1.70.0")] - fn is_terminal(&self) -> bool; -} +// /// Trait to determine if a descriptor/handle refers to a terminal/tty. +// #[stable(feature = "is_terminal", since = "1.70.0")] +// pub trait IsTerminal: crate::sealed::Sealed { +// /// Returns `true` if the descriptor/handle refers to a terminal/tty. +// /// +// /// On platforms where Rust does not know how to detect a terminal yet, this will return +// /// `false`. This will also return `false` if an unexpected error occurred, such as from +// /// passing an invalid file descriptor. +// /// +// /// # Platform-specific behavior +// /// +// /// On Windows, in addition to detecting consoles, this currently uses some heuristics to +// /// detect older msys/cygwin/mingw pseudo-terminals based on device name: devices with names +// /// starting with `msys-` or `cygwin-` and ending in `-pty` will be considered terminals. +// /// Note that this [may change in the future][changes]. +// /// +// /// # Examples +// /// +// /// An example of a type for which `IsTerminal` is implemented is [`Stdin`]: +// /// +// /// ```no_run +// /// use std::io::{self, IsTerminal, Write}; +// /// +// /// fn main() -> io::Result<()> { +// /// let stdin = io::stdin(); +// /// +// /// // Indicate that the user is prompted for input, if this is a terminal. +// /// if stdin.is_terminal() { +// /// print!("> "); +// /// io::stdout().flush()?; +// /// } +// /// +// /// let mut name = String::new(); +// /// let _ = stdin.read_line(&mut name)?; +// /// +// /// println!("Hello {}", name.trim_end()); +// /// +// /// Ok(()) +// /// } +// /// ``` +// /// +// /// The example can be run in two ways: +// /// +// /// - If you run this example by piping some text to it, e.g. `echo "foo" | path/to/executable` +// /// it will print: `Hello foo`. +// /// - If you instead run the example interactively by running `path/to/executable` directly, it will +// /// prompt for input. +// /// +// /// [changes]: io#platform-specific-behavior +// /// [`Stdin`]: crate::io::Stdin +// #[doc(alias = "isatty")] +// #[stable(feature = "is_terminal", since = "1.70.0")] +// fn is_terminal(&self) -> bool; +// } -macro_rules! impl_is_terminal { - ($($t:ty),*$(,)?) => {$( - #[unstable(feature = "sealed", issue = "none")] - impl crate::sealed::Sealed for $t {} +// macro_rules! impl_is_terminal { +// ($($t:ty),*$(,)?) => {$( +// #[unstable(feature = "sealed", issue = "none")] +// impl crate::sealed::Sealed for $t {} - #[stable(feature = "is_terminal", since = "1.70.0")] - impl IsTerminal for $t { - #[inline] - fn is_terminal(&self) -> bool { - crate::sys::io::is_terminal(self) - } - } - )*} -} +// #[stable(feature = "is_terminal", since = "1.70.0")] +// impl IsTerminal for $t { +// #[inline] +// fn is_terminal(&self) -> bool { +// crate::sys::io::is_terminal(self) +// } +// } +// )*} +// } -impl_is_terminal!(File, Stdin, StdinLock<'_>, Stdout, StdoutLock<'_>, Stderr, StderrLock<'_>); +// impl_is_terminal!(File, Stdin, StdinLock<'_>, Stdout, StdoutLock<'_>, Stderr, StderrLock<'_>); -#[unstable( - feature = "print_internals", - reason = "implementation detail which may disappear or be replaced at any time", - issue = "none" -)] -#[doc(hidden)] -#[cfg(not(test))] -pub fn _print(args: fmt::Arguments<'_>) { - print_to(args, stdout, "stdout"); -} +// #[unstable( +// feature = "print_internals", +// reason = "implementation detail which may disappear or be replaced at any time", +// issue = "none" +// )] +// #[doc(hidden)] +// #[cfg(not(test))] +// pub fn _print(args: fmt::Arguments<'_>) { +// print_to(args, stdout, "stdout"); +// } -#[unstable( - feature = "print_internals", - reason = "implementation detail which may disappear or be replaced at any time", - issue = "none" -)] -#[doc(hidden)] -#[cfg(not(test))] -pub fn _eprint(args: fmt::Arguments<'_>) { - print_to(args, stderr, "stderr"); -} +// #[unstable( +// feature = "print_internals", +// reason = "implementation detail which may disappear or be replaced at any time", +// issue = "none" +// )] +// #[doc(hidden)] +// #[cfg(not(test))] +// pub fn _eprint(args: fmt::Arguments<'_>) { +// print_to(args, stderr, "stderr"); +// } -#[cfg(test)] -pub use realstd::io::{_eprint, _print}; +// #[cfg(test)] +// pub use realstd::io::{_eprint, _print}; diff --git a/crates/std/src/lib.rs b/crates/std/src/lib.rs index bdf313c..3afee45 100644 --- a/crates/std/src/lib.rs +++ b/crates/std/src/lib.rs @@ -267,6 +267,11 @@ pub use core::{ stringify, trace_macros, }; +#[rustc_std_internal_symbol] +pub unsafe fn __rust_start_panic(_payload: &mut dyn core::panic::PanicPayload) -> u32 { + todo!() +} + pub mod ffi; pub mod hash; pub mod io; @@ -280,6 +285,10 @@ pub mod process; pub mod rt; pub mod alloc; pub mod bstr; +pub mod collections; +pub mod env; +pub mod panic; +pub mod panicking; pub mod sync; pub mod sys; pub mod thread; diff --git a/crates/std/src/panic.rs b/crates/std/src/panic.rs new file mode 100644 index 0000000..658026a --- /dev/null +++ b/crates/std/src/panic.rs @@ -0,0 +1,534 @@ +//! Panic support in the standard library. + +#![stable(feature = "std_panic", since = "1.9.0")] + +use crate::any::Any; +use crate::sync::atomic::{Atomic, AtomicU8, Ordering}; +use crate::sync::{Condvar, Mutex, RwLock}; +use crate::thread::Result; +use crate::{collections, fmt, panicking}; + +#[stable(feature = "panic_hooks", since = "1.10.0")] +#[deprecated( + since = "1.82.0", + note = "use `PanicHookInfo` instead", + suggestion = "std::panic::PanicHookInfo" +)] +/// A struct providing information about a panic. +/// +/// `PanicInfo` has been renamed to [`PanicHookInfo`] to avoid confusion with +/// [`core::panic::PanicInfo`]. +pub type PanicInfo<'a> = PanicHookInfo<'a>; + +/// A struct providing information about a panic. +/// +/// `PanicHookInfo` structure is passed to a panic hook set by the [`set_hook`] function. +/// +/// # Examples +/// +/// ```should_panic +/// use std::panic; +/// +/// panic::set_hook(Box::new(|panic_info| { +/// println!("panic occurred: {panic_info}"); +/// })); +/// +/// panic!("critical system failure"); +/// ``` +/// +/// [`set_hook`]: ../../std/panic/fn.set_hook.html +#[stable(feature = "panic_hook_info", since = "1.81.0")] +#[derive(Debug)] +pub struct PanicHookInfo<'a> { + payload: &'a (dyn Any + Send), + location: &'a Location<'a>, + can_unwind: bool, + force_no_backtrace: bool, +} + +impl<'a> PanicHookInfo<'a> { + #[inline] + pub(crate) fn new( + location: &'a Location<'a>, + payload: &'a (dyn Any + Send), + can_unwind: bool, + force_no_backtrace: bool, + ) -> Self { + PanicHookInfo { payload, location, can_unwind, force_no_backtrace } + } + + /// Returns the payload associated with the panic. + /// + /// This will commonly, but not always, be a `&'static str` or [`String`]. + /// If you only care about such payloads, use [`payload_as_str`] instead. + /// + /// A invocation of the `panic!()` macro in Rust 2021 or later will always result in a + /// panic payload of type `&'static str` or `String`. + /// + /// Only an invocation of [`panic_any`] + /// (or, in Rust 2018 and earlier, `panic!(x)` where `x` is something other than a string) + /// can result in a panic payload other than a `&'static str` or `String`. + /// + /// [`String`]: ../../std/string/struct.String.html + /// [`payload_as_str`]: PanicHookInfo::payload_as_str + /// + /// # Examples + /// + /// ```should_panic + /// use std::panic; + /// + /// panic::set_hook(Box::new(|panic_info| { + /// if let Some(s) = panic_info.payload().downcast_ref::<&str>() { + /// println!("panic occurred: {s:?}"); + /// } else if let Some(s) = panic_info.payload().downcast_ref::() { + /// println!("panic occurred: {s:?}"); + /// } else { + /// println!("panic occurred"); + /// } + /// })); + /// + /// panic!("Normal panic"); + /// ``` + #[must_use] + #[inline] + #[stable(feature = "panic_hooks", since = "1.10.0")] + pub fn payload(&self) -> &(dyn Any + Send) { + self.payload + } + + /// Returns the payload associated with the panic, if it is a string. + /// + /// This returns the payload if it is of type `&'static str` or `String`. + /// + /// A invocation of the `panic!()` macro in Rust 2021 or later will always result in a + /// panic payload where `payload_as_str` returns `Some`. + /// + /// Only an invocation of [`panic_any`] + /// (or, in Rust 2018 and earlier, `panic!(x)` where `x` is something other than a string) + /// can result in a panic payload where `payload_as_str` returns `None`. + /// + /// # Example + /// + /// ```should_panic + /// std::panic::set_hook(Box::new(|panic_info| { + /// if let Some(s) = panic_info.payload_as_str() { + /// println!("panic occurred: {s:?}"); + /// } else { + /// println!("panic occurred"); + /// } + /// })); + /// + /// panic!("Normal panic"); + /// ``` + #[must_use] + #[inline] + #[stable(feature = "panic_payload_as_str", since = "1.91.0")] + pub fn payload_as_str(&self) -> Option<&str> { + if let Some(s) = self.payload.downcast_ref::<&str>() { + Some(s) + } else if let Some(s) = self.payload.downcast_ref::() { + Some(s) + } else { + None + } + } + + /// Returns information about the location from which the panic originated, + /// if available. + /// + /// This method will currently always return [`Some`], but this may change + /// in future versions. + /// + /// # Examples + /// + /// ```should_panic + /// use std::panic; + /// + /// panic::set_hook(Box::new(|panic_info| { + /// if let Some(location) = panic_info.location() { + /// println!("panic occurred in file '{}' at line {}", + /// location.file(), + /// location.line(), + /// ); + /// } else { + /// println!("panic occurred but can't get location information..."); + /// } + /// })); + /// + /// panic!("Normal panic"); + /// ``` + #[must_use] + #[inline] + #[stable(feature = "panic_hooks", since = "1.10.0")] + pub fn location(&self) -> Option<&Location<'_>> { + // NOTE: If this is changed to sometimes return None, + // deal with that case in std::panicking::default_hook and core::panicking::panic_fmt. + Some(&self.location) + } + + /// Returns whether the panic handler is allowed to unwind the stack from + /// the point where the panic occurred. + /// + /// This is true for most kinds of panics with the exception of panics + /// caused by trying to unwind out of a `Drop` implementation or a function + /// whose ABI does not support unwinding. + /// + /// It is safe for a panic handler to unwind even when this function returns + /// false, however this will simply cause the panic handler to be called + /// again. + #[must_use] + #[inline] + #[unstable(feature = "panic_can_unwind", issue = "92988")] + pub fn can_unwind(&self) -> bool { + self.can_unwind + } + + #[unstable( + feature = "panic_internals", + reason = "internal details of the implementation of the `panic!` and related macros", + issue = "none" + )] + #[doc(hidden)] + #[inline] + pub fn force_no_backtrace(&self) -> bool { + self.force_no_backtrace + } +} + +#[stable(feature = "panic_hook_display", since = "1.26.0")] +impl fmt::Display for PanicHookInfo<'_> { + fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + formatter.write_str("panicked at ")?; + self.location.fmt(formatter)?; + if let Some(payload) = self.payload_as_str() { + formatter.write_str(":\n")?; + formatter.write_str(payload)?; + } + Ok(()) + } +} + +#[doc(hidden)] +#[unstable(feature = "edition_panic", issue = "none", reason = "use panic!() instead")] +#[allow_internal_unstable(libstd_sys_internals, const_format_args, panic_internals, rt)] +#[cfg_attr(not(test), rustc_diagnostic_item = "std_panic_2015_macro")] +#[rustc_macro_transparency = "semiopaque"] +pub macro panic_2015 { + () => ({ + $crate::rt::begin_panic("explicit panic") + }), + ($msg:expr $(,)?) => ({ + $crate::rt::begin_panic($msg); + }), + // Special-case the single-argument case for const_panic. + ("{}", $arg:expr $(,)?) => ({ + $crate::rt::panic_display(&$arg); + }), + ($fmt:expr, $($arg:tt)+) => ({ + // Semicolon to prevent temporaries inside the formatting machinery from + // being considered alive in the caller after the panic_fmt call. + $crate::rt::panic_fmt($crate::const_format_args!($fmt, $($arg)+)); + }), +} + +#[stable(feature = "panic_hooks", since = "1.10.0")] +pub use core::panic::Location; +#[doc(hidden)] +#[unstable(feature = "edition_panic", issue = "none", reason = "use panic!() instead")] +pub use core::panic::panic_2021; +#[stable(feature = "catch_unwind", since = "1.9.0")] +pub use core::panic::{AssertUnwindSafe, RefUnwindSafe, UnwindSafe}; + +#[unstable(feature = "panic_update_hook", issue = "92649")] +pub use crate::panicking::update_hook; +#[stable(feature = "panic_hooks", since = "1.10.0")] +pub use crate::panicking::{set_hook, take_hook}; + +/// Panics the current thread with the given message as the panic payload. +/// +/// The message can be of any (`Any + Send`) type, not just strings. +/// +/// The message is wrapped in a `Box<'static + Any + Send>`, which can be +/// accessed later using [`PanicHookInfo::payload`]. +/// +/// See the [`panic!`] macro for more information about panicking. +#[stable(feature = "panic_any", since = "1.51.0")] +#[inline] +#[track_caller] +#[cfg_attr(not(test), rustc_diagnostic_item = "panic_any")] +pub fn panic_any(msg: M) -> ! { + crate::panicking::begin_panic(msg); +} + +#[stable(feature = "catch_unwind", since = "1.9.0")] +impl UnwindSafe for Mutex {} +#[stable(feature = "catch_unwind", since = "1.9.0")] +impl UnwindSafe for RwLock {} +#[stable(feature = "catch_unwind", since = "1.9.0")] +impl UnwindSafe for Condvar {} + +#[stable(feature = "unwind_safe_lock_refs", since = "1.12.0")] +impl RefUnwindSafe for Mutex {} +#[stable(feature = "unwind_safe_lock_refs", since = "1.12.0")] +impl RefUnwindSafe for RwLock {} +#[stable(feature = "unwind_safe_lock_refs", since = "1.12.0")] +impl RefUnwindSafe for Condvar {} + +// https://github.com/rust-lang/rust/issues/62301 +#[stable(feature = "hashbrown", since = "1.36.0")] +impl UnwindSafe for collections::HashMap +where + K: UnwindSafe, + V: UnwindSafe, + S: UnwindSafe, +{ +} + +#[unstable(feature = "abort_unwind", issue = "130338")] +pub use core::panic::abort_unwind; + +/// Invokes a closure, capturing the cause of an unwinding panic if one occurs. +/// +/// This function will return `Ok` with the closure's result if the closure does +/// not panic, and will return `Err(cause)` if the closure panics. The `cause` +/// returned is the object with which panic was originally invoked. +/// +/// Rust functions that are expected to be called from foreign code that does +/// not support unwinding (such as C compiled with `-fno-exceptions`) should be +/// defined using `extern "C"`, which ensures that if the Rust code panics, it +/// is automatically caught and the process is aborted. If this is the desired +/// behavior, it is not necessary to use `catch_unwind` explicitly. This +/// function should instead be used when more graceful error-handling is needed. +/// +/// It is **not** recommended to use this function for a general try/catch +/// mechanism. The [`Result`] type is more appropriate to use for functions that +/// can fail on a regular basis. Additionally, this function is not guaranteed +/// to catch all panics, see the "Notes" section below. +/// +/// The closure provided is required to adhere to the [`UnwindSafe`] trait to +/// ensure that all captured variables are safe to cross this boundary. The +/// purpose of this bound is to encode the concept of [exception safety][rfc] in +/// the type system. Most usage of this function should not need to worry about +/// this bound as programs are naturally unwind safe without `unsafe` code. If +/// it becomes a problem the [`AssertUnwindSafe`] wrapper struct can be used to +/// quickly assert that the usage here is indeed unwind safe. +/// +/// [rfc]: https://github.com/rust-lang/rfcs/blob/master/text/1236-stabilize-catch-panic.md +/// +/// # Notes +/// +/// This function **might not catch all Rust panics**. A Rust panic is not +/// always implemented via unwinding, but can be implemented by aborting the +/// process as well. This function *only* catches unwinding panics, not those +/// that abort the process. +/// +/// If a custom panic hook has been set, it will be invoked before the panic is +/// caught, before unwinding. +/// +/// Although unwinding into Rust code with a foreign exception (e.g. an +/// exception thrown from C++ code, or a `panic!` in Rust code compiled or +/// linked with a different runtime) via an appropriate ABI (e.g. `"C-unwind"`) +/// is permitted, catching such an exception using this function will have one +/// of two behaviors, and it is unspecified which will occur: +/// +/// * The process aborts, after executing all destructors of `f` and the +/// functions it called. +/// * The function returns a `Result::Err` containing an opaque type. +/// +/// Finally, be **careful in how you drop the result of this function**. If it +/// is `Err`, it contains the panic payload, and dropping that may in turn +/// panic! +/// +/// # Examples +/// +/// ``` +/// use std::panic; +/// +/// let result = panic::catch_unwind(|| { +/// println!("hello!"); +/// }); +/// assert!(result.is_ok()); +/// +/// let result = panic::catch_unwind(|| { +/// panic!("oh no!"); +/// }); +/// assert!(result.is_err()); +/// ``` +#[stable(feature = "catch_unwind", since = "1.9.0")] +pub fn catch_unwind R + UnwindSafe, R>(f: F) -> Result { + unsafe { panicking::catch_unwind(f) } +} + +/// Triggers a panic without invoking the panic hook. +/// +/// This is designed to be used in conjunction with [`catch_unwind`] to, for +/// example, carry a panic across a layer of C code. +/// +/// # Notes +/// +/// Note that panics in Rust are not always implemented via unwinding, but they +/// may be implemented by aborting the process. If this function is called when +/// panics are implemented this way then this function will abort the process, +/// not trigger an unwind. +/// +/// # Examples +/// +/// ```should_panic +/// use std::panic; +/// +/// let result = panic::catch_unwind(|| { +/// if 1 != 2 { +/// panic!("oh no!"); +/// } +/// }); +/// +/// if let Err(err) = result { +/// panic::resume_unwind(err); +/// } +/// ``` +#[stable(feature = "resume_unwind", since = "1.9.0")] +pub fn resume_unwind(payload: Box) -> ! { + panicking::resume_unwind(payload) +} + +/// Makes all future panics abort directly without running the panic hook or unwinding. +/// +/// There is no way to undo this; the effect lasts until the process exits or +/// execs (or the equivalent). +/// +/// # Use after fork +/// +/// This function is particularly useful for calling after `libc::fork`. After `fork`, in a +/// multithreaded program it is (on many platforms) not safe to call the allocator. It is also +/// generally highly undesirable for an unwind to unwind past the `fork`, because that results in +/// the unwind propagating to code that was only ever expecting to run in the parent. +/// +/// `panic::always_abort()` helps avoid both of these. It directly avoids any further unwinding, +/// and if there is a panic, the abort will occur without allocating provided that the arguments to +/// panic can be formatted without allocating. +/// +/// Examples +/// +/// ```no_run +/// #![feature(panic_always_abort)] +/// use std::panic; +/// +/// panic::always_abort(); +/// +/// let _ = panic::catch_unwind(|| { +/// panic!("inside the catch"); +/// }); +/// +/// // We will have aborted already, due to the panic. +/// unreachable!(); +/// ``` +#[unstable(feature = "panic_always_abort", issue = "84438")] +pub fn always_abort() { + crate::panicking::panic_count::set_always_abort(); +} + +/// The configuration for whether and how the default panic hook will capture +/// and display the backtrace. +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +#[unstable(feature = "panic_backtrace_config", issue = "93346")] +#[non_exhaustive] +pub enum BacktraceStyle { + /// Prints a terser backtrace which ideally only contains relevant + /// information. + Short, + /// Prints a backtrace with all possible information. + Full, + /// Disable collecting and displaying backtraces. + Off, +} + +impl BacktraceStyle { + pub(crate) fn full() -> Option { + if cfg!(feature = "backtrace") { Some(BacktraceStyle::Full) } else { None } + } + + fn as_u8(self) -> u8 { + match self { + BacktraceStyle::Short => 1, + BacktraceStyle::Full => 2, + BacktraceStyle::Off => 3, + } + } + + fn from_u8(s: u8) -> Option { + match s { + 1 => Some(BacktraceStyle::Short), + 2 => Some(BacktraceStyle::Full), + 3 => Some(BacktraceStyle::Off), + _ => None, + } + } +} + +// Tracks whether we should/can capture a backtrace, and how we should display +// that backtrace. +// +// Internally stores equivalent of an Option. +static SHOULD_CAPTURE: Atomic = AtomicU8::new(0); + +/// Configures whether the default panic hook will capture and display a +/// backtrace. +/// +/// The default value for this setting may be set by the `RUST_BACKTRACE` +/// environment variable; see the details in [`get_backtrace_style`]. +#[unstable(feature = "panic_backtrace_config", issue = "93346")] +pub fn set_backtrace_style(style: BacktraceStyle) { + if cfg!(feature = "backtrace") { + // If the `backtrace` feature of this crate is enabled, set the backtrace style. + SHOULD_CAPTURE.store(style.as_u8(), Ordering::Relaxed); + } +} + +/// Checks whether the standard library's panic hook will capture and print a +/// backtrace. +/// +/// This function will, if a backtrace style has not been set via +/// [`set_backtrace_style`], read the environment variable `RUST_BACKTRACE` to +/// determine a default value for the backtrace formatting: +/// +/// The first call to `get_backtrace_style` may read the `RUST_BACKTRACE` +/// environment variable if `set_backtrace_style` has not been called to +/// override the default value. After a call to `set_backtrace_style` or +/// `get_backtrace_style`, any changes to `RUST_BACKTRACE` will have no effect. +/// +/// `RUST_BACKTRACE` is read according to these rules: +/// +/// * `0` for `BacktraceStyle::Off` +/// * `full` for `BacktraceStyle::Full` +/// * `1` for `BacktraceStyle::Short` +/// * Other values are currently `BacktraceStyle::Short`, but this may change in +/// the future +/// +/// Returns `None` if backtraces aren't currently supported. +#[unstable(feature = "panic_backtrace_config", issue = "93346")] +pub fn get_backtrace_style() -> Option { + if !cfg!(feature = "backtrace") { + // If the `backtrace` feature of this crate isn't enabled quickly return + // `Unsupported` so this can be constant propagated all over the place + // to optimize away callers. + return None; + } + + let current = SHOULD_CAPTURE.load(Ordering::Relaxed); + if let Some(style) = BacktraceStyle::from_u8(current) { + return Some(style); + } + + let format = match crate::env::var_os("RUST_BACKTRACE") { + Some(x) if &x == "0" => BacktraceStyle::Off, + Some(x) if &x == "full" => BacktraceStyle::Full, + Some(_) => BacktraceStyle::Short, + None if crate::sys::backtrace::FULL_BACKTRACE_DEFAULT => BacktraceStyle::Full, + None => BacktraceStyle::Off, + }; + + match SHOULD_CAPTURE.compare_exchange(0, format.as_u8(), Ordering::Relaxed, Ordering::Relaxed) { + Ok(_) => Some(format), + Err(new) => BacktraceStyle::from_u8(new), + } +} diff --git a/crates/std/src/panicking.rs b/crates/std/src/panicking.rs new file mode 100644 index 0000000..a21aafe --- /dev/null +++ b/crates/std/src/panicking.rs @@ -0,0 +1,894 @@ +//! Implementation of various bits and pieces of the `panic!` macro and +//! associated runtime pieces. +//! +//! Specifically, this module contains the implementation of: +//! +//! * Panic hooks +//! * Executing a panic up to doing the actual implementation +//! * Shims around "try" + +#![deny(unsafe_op_in_unsafe_fn)] + +use core::panic::{Location, PanicPayload}; + +// make sure to use the stderr output configured +// by libtest in the real copy of std +#[cfg(test)] +use realstd::io::try_set_output_capture; + +use crate::any::Any; +#[cfg(not(test))] +use crate::io::try_set_output_capture; +use crate::mem::{self, ManuallyDrop}; +use crate::panic::{BacktraceStyle, PanicHookInfo}; +use crate::sync::atomic::{Atomic, AtomicBool, Ordering}; +use crate::sync::nonpoison::RwLock; +use crate::sys::backtrace; +use crate::sys::stdio::panic_output; +use crate::{fmt, intrinsics, process, thread}; + +// This forces codegen of the function called by panic!() inside the std crate, rather than in +// downstream crates. Primarily this is useful for rustc's codegen tests, which rely on noticing +// complete removal of panic from generated IR. Since begin_panic is inline(never), it's only +// codegen'd once per crate-graph so this pushes that to std rather than our codegen test crates. +// +// (See https://github.com/rust-lang/rust/pull/123244 for more info on why). +// +// If this is causing problems we can also modify those codegen tests to use a crate type like +// cdylib which doesn't export "Rust" symbols to downstream linkage units. +#[unstable(feature = "libstd_sys_internals", reason = "used by the panic! macro", issue = "none")] +#[doc(hidden)] +#[allow(dead_code)] +#[used(compiler)] +pub static EMPTY_PANIC: fn(&'static str) -> ! = + begin_panic::<&'static str> as fn(&'static str) -> !; + +// Binary interface to the panic runtime that the standard library depends on. +// +// The standard library is tagged with `#![needs_panic_runtime]` (introduced in +// RFC 1513) to indicate that it requires some other crate tagged with +// `#![panic_runtime]` to exist somewhere. Each panic runtime is intended to +// implement these symbols (with the same signatures) so we can get matched up +// to them. +// +// One day this may look a little less ad-hoc with the compiler helping out to +// hook up these functions, but it is not this day! +#[allow(improper_ctypes)] +unsafe extern "C" { + #[rustc_std_internal_symbol] + fn __rust_panic_cleanup(payload: *mut u8) -> *mut (dyn Any + Send + 'static); +} + +unsafe extern "Rust" { + /// `PanicPayload` lazily performs allocation only when needed (this avoids + /// allocations when using the "abort" panic runtime). + #[rustc_std_internal_symbol] + fn __rust_start_panic(payload: &mut dyn PanicPayload) -> u32; +} + +/// This function is called by the panic runtime if FFI code catches a Rust +/// panic but doesn't rethrow it. We don't support this case since it messes +/// with our panic count. +#[cfg(not(test))] +#[rustc_std_internal_symbol] +extern "C" fn __rust_drop_panic() -> ! { + rtabort!("Rust panics must be rethrown"); +} + +/// This function is called by the panic runtime if it catches an exception +/// object which does not correspond to a Rust panic. +#[cfg(not(test))] +#[rustc_std_internal_symbol] +extern "C" fn __rust_foreign_exception() -> ! { + rtabort!("Rust cannot catch foreign exceptions"); +} + +#[derive(Default)] +enum Hook { + #[default] + Default, + Custom(Box) + 'static + Sync + Send>), +} + +impl Hook { + #[inline] + fn into_box(self) -> Box) + 'static + Sync + Send> { + match self { + Hook::Default => Box::new(default_hook), + Hook::Custom(hook) => hook, + } + } +} + +static HOOK: RwLock = RwLock::new(Hook::Default); + +/// Registers a custom panic hook, replacing the previously registered hook. +/// +/// The panic hook is invoked when a thread panics, but before the panic runtime +/// is invoked. As such, the hook will run with both the aborting and unwinding +/// runtimes. +/// +/// The default hook, which is registered at startup, prints a message to standard error and +/// generates a backtrace if requested. This behavior can be customized using the `set_hook` function. +/// The current hook can be retrieved while reinstating the default hook with the [`take_hook`] +/// function. +/// +/// [`take_hook`]: ./fn.take_hook.html +/// +/// The hook is provided with a `PanicHookInfo` struct which contains information +/// about the origin of the panic, including the payload passed to `panic!` and +/// the source code location from which the panic originated. +/// +/// The panic hook is a global resource. +/// +/// # Panics +/// +/// Panics if called from a panicking thread. +/// +/// # Examples +/// +/// The following will print "Custom panic hook": +/// +/// ```should_panic +/// use std::panic; +/// +/// panic::set_hook(Box::new(|_| { +/// println!("Custom panic hook"); +/// })); +/// +/// panic!("Normal panic"); +/// ``` +#[stable(feature = "panic_hooks", since = "1.10.0")] +pub fn set_hook(hook: Box) + 'static + Sync + Send>) { + if thread::panicking() { + panic!("cannot modify the panic hook from a panicking thread"); + } + + // Drop the old hook after changing the hook to avoid deadlocking if its + // destructor panics. + drop(HOOK.replace(Hook::Custom(hook))); +} + +/// Unregisters the current panic hook and returns it, registering the default hook +/// in its place. +/// +/// *See also the function [`set_hook`].* +/// +/// [`set_hook`]: ./fn.set_hook.html +/// +/// If the default hook is registered it will be returned, but remain registered. +/// +/// # Panics +/// +/// Panics if called from a panicking thread. +/// +/// # Examples +/// +/// The following will print "Normal panic": +/// +/// ```should_panic +/// use std::panic; +/// +/// panic::set_hook(Box::new(|_| { +/// println!("Custom panic hook"); +/// })); +/// +/// let _ = panic::take_hook(); +/// +/// panic!("Normal panic"); +/// ``` +#[must_use] +#[stable(feature = "panic_hooks", since = "1.10.0")] +pub fn take_hook() -> Box) + 'static + Sync + Send> { + if thread::panicking() { + panic!("cannot modify the panic hook from a panicking thread"); + } + + HOOK.replace(Hook::Default).into_box() +} + +/// Atomic combination of [`take_hook`] and [`set_hook`]. Use this to replace the panic handler with +/// a new panic handler that does something and then executes the old handler. +/// +/// [`take_hook`]: ./fn.take_hook.html +/// [`set_hook`]: ./fn.set_hook.html +/// +/// # Panics +/// +/// Panics if called from a panicking thread. +/// +/// # Examples +/// +/// The following will print the custom message, and then the normal output of panic. +/// +/// ```should_panic +/// #![feature(panic_update_hook)] +/// use std::panic; +/// +/// // Equivalent to +/// // let prev = panic::take_hook(); +/// // panic::set_hook(Box::new(move |info| { +/// // println!("..."); +/// // prev(info); +/// // })); +/// panic::update_hook(move |prev, info| { +/// println!("Print custom message and execute panic handler as usual"); +/// prev(info); +/// }); +/// +/// panic!("Custom and then normal"); +/// ``` +#[unstable(feature = "panic_update_hook", issue = "92649")] +pub fn update_hook(hook_fn: F) +where + F: Fn(&(dyn Fn(&PanicHookInfo<'_>) + Send + Sync + 'static), &PanicHookInfo<'_>) + + Sync + + Send + + 'static, +{ + if thread::panicking() { + panic!("cannot modify the panic hook from a panicking thread"); + } + + let mut hook = HOOK.write(); + let prev = mem::take(&mut *hook).into_box(); + *hook = Hook::Custom(Box::new(move |info| hook_fn(&prev, info))); +} + +/// The default panic handler. +#[optimize(size)] +fn default_hook(info: &PanicHookInfo<'_>) { + // If this is a double panic, make sure that we print a backtrace + // for this panic. Otherwise only print it if logging is enabled. + let backtrace = if info.force_no_backtrace() { + None + } else if panic_count::get_count() >= 2 { + BacktraceStyle::full() + } else { + crate::panic::get_backtrace_style() + }; + + // The current implementation always returns `Some`. + let location = info.location().unwrap(); + + let msg = payload_as_str(info.payload()); + + let write = #[optimize(size)] + |err: &mut dyn crate::io::Write| { + // Use a lock to prevent mixed output in multithreading context. + // Some platforms also require it when printing a backtrace, like `SymFromAddr` on Windows. + let mut lock = backtrace::lock(); + + thread::with_current_name(|name| { + let name = name.unwrap_or(""); + let tid = thread::current_os_id(); + + // Try to write the panic message to a buffer first to prevent other concurrent outputs + // interleaving with it. + let mut buffer = [0u8; 512]; + let mut cursor = crate::io::Cursor::new(&mut buffer[..]); + + let write_msg = |dst: &mut dyn crate::io::Write| { + // We add a newline to ensure the panic message appears at the start of a line. + writeln!(dst, "\nthread '{name}' ({tid}) panicked at {location}:\n{msg}") + }; + + if write_msg(&mut cursor).is_ok() { + let pos = cursor.position() as usize; + let _ = err.write_all(&buffer[0..pos]); + } else { + // The message did not fit into the buffer, write it directly instead. + let _ = write_msg(err); + }; + }); + + static FIRST_PANIC: Atomic = AtomicBool::new(true); + + match backtrace { + Some(BacktraceStyle::Short) => { + todo!() + } + Some(BacktraceStyle::Full) => { + todo!() + } + Some(BacktraceStyle::Off) => { + if FIRST_PANIC.swap(false, Ordering::Relaxed) { + let _ = writeln!( + err, + "note: run with `RUST_BACKTRACE=1` environment variable to display a \ + backtrace" + ); + if cfg!(miri) { + let _ = writeln!( + err, + "note: in Miri, you may have to set `MIRIFLAGS=-Zmiri-env-forward=RUST_BACKTRACE` \ + for the environment variable to have an effect" + ); + } + } + } + // If backtraces aren't supported or are forced-off, do nothing. + None => {} + } + }; + + if let Ok(Some(local)) = try_set_output_capture(None) { + write(&mut *local.lock().unwrap_or_else(|e| e.into_inner())); + try_set_output_capture(Some(local)).ok(); + } else if let Some(mut out) = panic_output() { + write(&mut out); + } +} + +#[cfg(not(test))] +#[doc(hidden)] +#[cfg(panic = "immediate-abort")] +#[unstable(feature = "update_panic_count", issue = "none")] +pub mod panic_count { + /// A reason for forcing an immediate abort on panic. + #[derive(Debug)] + pub enum MustAbort { + AlwaysAbort, + PanicInHook, + } + + #[inline] + pub fn increase(run_panic_hook: bool) -> Option { + None + } + + #[inline] + pub fn finished_panic_hook() {} + + #[inline] + pub fn decrease() {} + + #[inline] + pub fn set_always_abort() {} + + // Disregards ALWAYS_ABORT_FLAG + #[inline] + #[must_use] + pub fn get_count() -> usize { + 0 + } + + #[must_use] + #[inline] + pub fn count_is_zero() -> bool { + true + } +} + +#[cfg(not(test))] +#[doc(hidden)] +#[cfg(not(panic = "immediate-abort"))] +#[unstable(feature = "update_panic_count", issue = "none")] +pub mod panic_count { + use crate::cell::Cell; + use crate::sync::atomic::{Atomic, AtomicUsize, Ordering}; + + const ALWAYS_ABORT_FLAG: usize = 1 << (usize::BITS - 1); + + /// A reason for forcing an immediate abort on panic. + #[derive(Debug)] + pub enum MustAbort { + AlwaysAbort, + PanicInHook, + } + + // Panic count for the current thread and whether a panic hook is currently + // being executed.. + thread_local! { + static LOCAL_PANIC_COUNT: Cell<(usize, bool)> = const { Cell::new((0, false)) } + } + + // Sum of panic counts from all threads. The purpose of this is to have + // a fast path in `count_is_zero` (which is used by `panicking`). In any particular + // thread, if that thread currently views `GLOBAL_PANIC_COUNT` as being zero, + // then `LOCAL_PANIC_COUNT` in that thread is zero. This invariant holds before + // and after increase and decrease, but not necessarily during their execution. + // + // Additionally, the top bit of GLOBAL_PANIC_COUNT (GLOBAL_ALWAYS_ABORT_FLAG) + // records whether panic::always_abort() has been called. This can only be + // set, never cleared. + // panic::always_abort() is usually called to prevent memory allocations done by + // the panic handling in the child created by `libc::fork`. + // Memory allocations performed in a child created with `libc::fork` are undefined + // behavior in most operating systems. + // Accessing LOCAL_PANIC_COUNT in a child created by `libc::fork` would lead to a memory + // allocation. Only GLOBAL_PANIC_COUNT can be accessed in this situation. This is + // sufficient because a child process will always have exactly one thread only. + // See also #85261 for details. + // + // This could be viewed as a struct containing a single bit and an n-1-bit + // value, but if we wrote it like that it would be more than a single word, + // and even a newtype around usize would be clumsy because we need atomics. + // But we use such a tuple for the return type of increase(). + // + // Stealing a bit is fine because it just amounts to assuming that each + // panicking thread consumes at least 2 bytes of address space. + static GLOBAL_PANIC_COUNT: Atomic = AtomicUsize::new(0); + + // Increases the global and local panic count, and returns whether an + // immediate abort is required. + // + // This also updates thread-local state to keep track of whether a panic + // hook is currently executing. + pub fn increase(run_panic_hook: bool) -> Option { + let global_count = GLOBAL_PANIC_COUNT.fetch_add(1, Ordering::Relaxed); + if global_count & ALWAYS_ABORT_FLAG != 0 { + // Do *not* access thread-local state, we might be after a `fork`. + return Some(MustAbort::AlwaysAbort); + } + + LOCAL_PANIC_COUNT.with(|c| { + let (count, in_panic_hook) = c.get(); + if in_panic_hook { + return Some(MustAbort::PanicInHook); + } + c.set((count + 1, run_panic_hook)); + None + }) + } + + pub fn finished_panic_hook() { + LOCAL_PANIC_COUNT.with(|c| { + let (count, _) = c.get(); + c.set((count, false)); + }); + } + + pub fn decrease() { + GLOBAL_PANIC_COUNT.fetch_sub(1, Ordering::Relaxed); + LOCAL_PANIC_COUNT.with(|c| { + let (count, _) = c.get(); + c.set((count - 1, false)); + }); + } + + pub fn set_always_abort() { + GLOBAL_PANIC_COUNT.fetch_or(ALWAYS_ABORT_FLAG, Ordering::Relaxed); + } + + // Disregards ALWAYS_ABORT_FLAG + #[must_use] + pub fn get_count() -> usize { + LOCAL_PANIC_COUNT.with(|c| c.get().0) + } + + // Disregards ALWAYS_ABORT_FLAG + #[must_use] + #[inline] + pub fn count_is_zero() -> bool { + if GLOBAL_PANIC_COUNT.load(Ordering::Relaxed) & !ALWAYS_ABORT_FLAG == 0 { + // Fast path: if `GLOBAL_PANIC_COUNT` is zero, all threads + // (including the current one) will have `LOCAL_PANIC_COUNT` + // equal to zero, so TLS access can be avoided. + // + // In terms of performance, a relaxed atomic load is similar to a normal + // aligned memory read (e.g., a mov instruction in x86), but with some + // compiler optimization restrictions. On the other hand, a TLS access + // might require calling a non-inlinable function (such as `__tls_get_addr` + // when using the GD TLS model). + true + } else { + is_zero_slow_path() + } + } + + // Slow path is in a separate function to reduce the amount of code + // inlined from `count_is_zero`. + #[inline(never)] + #[cold] + fn is_zero_slow_path() -> bool { + LOCAL_PANIC_COUNT.with(|c| c.get().0 == 0) + } +} + +#[cfg(test)] +pub use realstd::rt::panic_count; + +/// Invoke a closure, capturing the cause of an unwinding panic if one occurs. +#[cfg(panic = "immediate-abort")] +pub unsafe fn catch_unwind R>(f: F) -> Result> { + Ok(f()) +} + +/// Invoke a closure, capturing the cause of an unwinding panic if one occurs. +#[cfg(not(panic = "immediate-abort"))] +pub unsafe fn catch_unwind R>(f: F) -> Result> { + union Data { + f: ManuallyDrop, + r: ManuallyDrop, + p: ManuallyDrop>, + } + + // We do some sketchy operations with ownership here for the sake of + // performance. We can only pass pointers down to `do_call` (can't pass + // objects by value), so we do all the ownership tracking here manually + // using a union. + // + // We go through a transition where: + // + // * First, we set the data field `f` to be the argumentless closure that we're going to call. + // * When we make the function call, the `do_call` function below, we take + // ownership of the function pointer. At this point the `data` union is + // entirely uninitialized. + // * If the closure successfully returns, we write the return value into the + // data's return slot (field `r`). + // * If the closure panics (`do_catch` below), we write the panic payload into field `p`. + // * Finally, when we come back out of the `try` intrinsic we're + // in one of two states: + // + // 1. The closure didn't panic, in which case the return value was + // filled in. We move it out of `data.r` and return it. + // 2. The closure panicked, in which case the panic payload was + // filled in. We move it out of `data.p` and return it. + // + // Once we stack all that together we should have the "most efficient' + // method of calling a catch panic whilst juggling ownership. + let mut data = Data { f: ManuallyDrop::new(f) }; + + let data_ptr = (&raw mut data) as *mut u8; + // SAFETY: + // + // Access to the union's fields: this is `std` and we know that the `catch_unwind` + // intrinsic fills in the `r` or `p` union field based on its return value. + // + // The call to `intrinsics::catch_unwind` is made safe by: + // - `do_call`, the first argument, can be called with the initial `data_ptr`. + // - `do_catch`, the second argument, can be called with the `data_ptr` as well. + // See their safety preconditions for more information + unsafe { + return if intrinsics::catch_unwind(do_call::, data_ptr, do_catch::) == 0 { + Ok(ManuallyDrop::into_inner(data.r)) + } else { + Err(ManuallyDrop::into_inner(data.p)) + }; + } + + // We consider unwinding to be rare, so mark this function as cold. However, + // do not mark it no-inline -- that decision is best to leave to the + // optimizer (in most cases this function is not inlined even as a normal, + // non-cold function, though, as of the writing of this comment). + #[cold] + #[optimize(size)] + unsafe fn cleanup(payload: *mut u8) -> Box { + // SAFETY: The whole unsafe block hinges on a correct implementation of + // the panic handler `__rust_panic_cleanup`. As such we can only + // assume it returns the correct thing for `Box::from_raw` to work + // without undefined behavior. + let obj = unsafe { Box::from_raw(__rust_panic_cleanup(payload)) }; + panic_count::decrease(); + obj + } + + // SAFETY: + // data must be non-NUL, correctly aligned, and a pointer to a `Data` + // Its must contains a valid `f` (type: F) value that can be use to fill + // `data.r`. + // + // This function cannot be marked as `unsafe` because `intrinsics::catch_unwind` + // expects normal function pointers. + #[inline] + fn do_call R, R>(data: *mut u8) { + // SAFETY: this is the responsibility of the caller, see above. + unsafe { + let data = data as *mut Data; + let data = &mut (*data); + let f = ManuallyDrop::take(&mut data.f); + data.r = ManuallyDrop::new(f()); + } + } + + // We *do* want this part of the catch to be inlined: this allows the + // compiler to properly track accesses to the Data union and optimize it + // away most of the time. + // + // SAFETY: + // data must be non-NUL, correctly aligned, and a pointer to a `Data` + // Since this uses `cleanup` it also hinges on a correct implementation of + // `__rustc_panic_cleanup`. + // + // This function cannot be marked as `unsafe` because `intrinsics::catch_unwind` + // expects normal function pointers. + #[inline] + #[rustc_nounwind] // `intrinsic::catch_unwind` requires catch fn to be nounwind + fn do_catch R, R>(data: *mut u8, payload: *mut u8) { + // SAFETY: this is the responsibility of the caller, see above. + // + // When `__rustc_panic_cleaner` is correctly implemented we can rely + // on `obj` being the correct thing to pass to `data.p` (after wrapping + // in `ManuallyDrop`). + unsafe { + let data = data as *mut Data; + let data = &mut (*data); + let obj = cleanup(payload); + data.p = ManuallyDrop::new(obj); + } + } +} + +/// Determines whether the current thread is unwinding because of panic. +#[inline] +pub fn panicking() -> bool { + !panic_count::count_is_zero() +} + +/// Entry point of panics from the core crate (`panic_impl` lang item). +#[cfg(not(any(test, doctest)))] +#[panic_handler] +pub fn panic_handler(info: &core::panic::PanicInfo<'_>) -> ! { + struct FormatStringPayload<'a> { + inner: &'a core::panic::PanicMessage<'a>, + string: Option, + } + + impl FormatStringPayload<'_> { + fn fill(&mut self) -> &mut String { + let inner = self.inner; + // Lazily, the first time this gets called, run the actual string formatting. + self.string.get_or_insert_with(|| { + let mut s = String::new(); + let mut fmt = fmt::Formatter::new(&mut s, fmt::FormattingOptions::new()); + let _err = fmt::Display::fmt(&inner, &mut fmt); + s + }) + } + } + + unsafe impl PanicPayload for FormatStringPayload<'_> { + fn take_box(&mut self) -> *mut (dyn Any + Send) { + // We do two allocations here, unfortunately. But (a) they're required with the current + // scheme, and (b) we don't handle panic + OOM properly anyway (see comment in + // begin_panic below). + let contents = mem::take(self.fill()); + Box::into_raw(Box::new(contents)) + } + + fn get(&mut self) -> &(dyn Any + Send) { + self.fill() + } + } + + impl fmt::Display for FormatStringPayload<'_> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + if let Some(s) = &self.string { + f.write_str(s) + } else { + fmt::Display::fmt(&self.inner, f) + } + } + } + + struct StaticStrPayload(&'static str); + + unsafe impl PanicPayload for StaticStrPayload { + fn take_box(&mut self) -> *mut (dyn Any + Send) { + Box::into_raw(Box::new(self.0)) + } + + fn get(&mut self) -> &(dyn Any + Send) { + &self.0 + } + + fn as_str(&mut self) -> Option<&str> { + Some(self.0) + } + } + + impl fmt::Display for StaticStrPayload { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(self.0) + } + } + + let loc = info.location().unwrap(); // The current implementation always returns Some + let msg = info.message(); + crate::sys::backtrace::__rust_end_short_backtrace(move || { + if let Some(s) = msg.as_str() { + panic_with_hook( + &mut StaticStrPayload(s), + loc, + info.can_unwind(), + info.force_no_backtrace(), + ); + } else { + panic_with_hook( + &mut FormatStringPayload { inner: &msg, string: None }, + loc, + info.can_unwind(), + info.force_no_backtrace(), + ); + } + }) +} + +/// This is the entry point of panicking for the non-format-string variants of +/// panic!() and assert!(). In particular, this is the only entry point that supports +/// arbitrary payloads, not just format strings. +#[unstable(feature = "libstd_sys_internals", reason = "used by the panic! macro", issue = "none")] +#[cfg_attr(not(any(test, doctest)), lang = "begin_panic")] +// lang item for CTFE panic support +// never inline unless panic=immediate-abort to avoid code +// bloat at the call sites as much as possible +#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold, optimize(size))] +#[cfg_attr(panic = "immediate-abort", inline)] +#[track_caller] +#[rustc_do_not_const_check] // hooked by const-eval +pub const fn begin_panic(msg: M) -> ! { + if cfg!(panic = "immediate-abort") { + intrinsics::abort() + } + + struct Payload { + inner: Option, + } + + unsafe impl PanicPayload for Payload { + fn take_box(&mut self) -> *mut (dyn Any + Send) { + // Note that this should be the only allocation performed in this code path. Currently + // this means that panic!() on OOM will invoke this code path, but then again we're not + // really ready for panic on OOM anyway. If we do start doing this, then we should + // propagate this allocation to be performed in the parent of this thread instead of the + // thread that's panicking. + let data = match self.inner.take() { + Some(a) => Box::new(a) as Box, + None => process::abort(), + }; + Box::into_raw(data) + } + + fn get(&mut self) -> &(dyn Any + Send) { + match self.inner { + Some(ref a) => a, + None => process::abort(), + } + } + } + + impl fmt::Display for Payload { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match &self.inner { + Some(a) => f.write_str(payload_as_str(a)), + None => process::abort(), + } + } + } + + let loc = Location::caller(); + crate::sys::backtrace::__rust_end_short_backtrace(move || { + panic_with_hook( + &mut Payload { inner: Some(msg) }, + loc, + /* can_unwind */ true, + /* force_no_backtrace */ false, + ) + }) +} + +fn payload_as_str(payload: &dyn Any) -> &str { + if let Some(&s) = payload.downcast_ref::<&'static str>() { + s + } else if let Some(s) = payload.downcast_ref::() { + s.as_str() + } else { + "Box" + } +} + +/// Central point for dispatching panics. +/// +/// Executes the primary logic for a panic, including checking for recursive +/// panics, panic hooks, and finally dispatching to the panic runtime to either +/// abort or unwind. +#[optimize(size)] +fn panic_with_hook( + payload: &mut dyn PanicPayload, + location: &Location<'_>, + can_unwind: bool, + force_no_backtrace: bool, +) -> ! { + let must_abort = panic_count::increase(true); + + // Check if we need to abort immediately. + if let Some(must_abort) = must_abort { + match must_abort { + panic_count::MustAbort::PanicInHook => { + // Don't try to format the message in this case, perhaps that is causing the + // recursive panics. However if the message is just a string, no user-defined + // code is involved in printing it, so that is risk-free. + let message: &str = payload.as_str().unwrap_or_default(); + rtprintpanic!( + "panicked at {location}:\n{message}\nthread panicked while processing panic. aborting.\n" + ); + } + panic_count::MustAbort::AlwaysAbort => { + // Unfortunately, this does not print a backtrace, because creating + // a `Backtrace` will allocate, which we must avoid here. + rtprintpanic!("aborting due to panic at {location}:\n{payload}\n"); + } + } + crate::process::abort(); + } + + match *HOOK.read() { + // Some platforms (like wasm) know that printing to stderr won't ever actually + // print anything, and if that's the case we can skip the default + // hook. Since string formatting happens lazily when calling `payload` + // methods, this means we avoid formatting the string at all! + // (The panic runtime might still call `payload.take_box()` though and trigger + // formatting.) + Hook::Default if panic_output().is_none() => {} + Hook::Default => { + default_hook(&PanicHookInfo::new( + location, + payload.get(), + can_unwind, + force_no_backtrace, + )); + } + Hook::Custom(ref hook) => { + hook(&PanicHookInfo::new(location, payload.get(), can_unwind, force_no_backtrace)); + } + } + + // Indicate that we have finished executing the panic hook. After this point + // it is fine if there is a panic while executing destructors, as long as it + // it contained within a `catch_unwind`. + panic_count::finished_panic_hook(); + + if !can_unwind { + // If a thread panics while running destructors or tries to unwind + // through a nounwind function (e.g. extern "C") then we cannot continue + // unwinding and have to abort immediately. + rtprintpanic!("thread caused non-unwinding panic. aborting.\n"); + crate::process::abort(); + } + + rust_panic(payload) +} + +/// This is the entry point for `resume_unwind`. +/// It just forwards the payload to the panic runtime. +#[cfg_attr(panic = "immediate-abort", inline)] +pub fn resume_unwind(payload: Box) -> ! { + panic_count::increase(false); + + struct RewrapBox(Box); + + unsafe impl PanicPayload for RewrapBox { + fn take_box(&mut self) -> *mut (dyn Any + Send) { + Box::into_raw(mem::replace(&mut self.0, Box::new(()))) + } + + fn get(&mut self) -> &(dyn Any + Send) { + &*self.0 + } + } + + impl fmt::Display for RewrapBox { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(payload_as_str(&self.0)) + } + } + + rust_panic(&mut RewrapBox(payload)) +} + +/// A function with a fixed suffix (through `rustc_std_internal_symbol`) +/// on which to slap yer breakpoints. +#[inline(never)] +#[cfg_attr(not(test), rustc_std_internal_symbol)] +#[cfg(not(panic = "immediate-abort"))] +fn rust_panic(msg: &mut dyn PanicPayload) -> ! { + let code = unsafe { __rust_start_panic(msg) }; + rtabort!("failed to initiate panic, error {code}") +} + +#[cfg_attr(not(test), rustc_std_internal_symbol)] +#[cfg(panic = "immediate-abort")] +fn rust_panic(_: &mut dyn PanicPayload) -> ! { + crate::intrinsics::abort(); +} diff --git a/crates/std/src/prelude.rs b/crates/std/src/prelude.rs index fe64410..2771679 100644 --- a/crates/std/src/prelude.rs +++ b/crates/std/src/prelude.rs @@ -150,11 +150,11 @@ pub mod rust_2024 { } } - #[panic_handler] - fn panic(_panic_info: &core::panic::PanicInfo) -> ! { - // TODO print - loop {} - } + // #[panic_handler] + // fn panic(_panic_info: &core::panic::PanicInfo) -> ! { + // // TODO print + // loop {} + // } /// # Safety /// `argc` and `argv` are passed by the kernel diff --git a/crates/std/src/process.rs b/crates/std/src/process.rs index 11e4ff4..d6ab4f1 100644 --- a/crates/std/src/process.rs +++ b/crates/std/src/process.rs @@ -27,3 +27,7 @@ impl Termination for isize { ExitCode(self) } } + +pub fn abort() -> ! { + loop {} +} diff --git a/crates/std/src/rt.rs b/crates/std/src/rt.rs index fe70585..a79dd3c 100644 --- a/crates/std/src/rt.rs +++ b/crates/std/src/rt.rs @@ -1,5 +1,7 @@ macro_rules! rtabort { - ($($t:tt)*) => {{}}; + ($($t:tt)*) => {{ + loop {} + }}; } macro_rules! rtprintpanic { ($($t:tt)*) => {{}}; diff --git a/crates/std/src/sync.rs b/crates/std/src/sync.rs index ea7b9bb..b494a67 100644 --- a/crates/std/src/sync.rs +++ b/crates/std/src/sync.rs @@ -16,10 +16,70 @@ pub use once::OnceState; pub use poison::LockResult; pub use poison::Mutex; +pub use poison::MutexGuard; pub use poison::PoisonError; pub use poison::TryLockError; pub use poison::TryLockResult; +pub use poison::Condvar; +pub use poison::RwLock; +pub use once_lock::OnceLock; +pub use reentrant_lock::ReentrantLock; +pub use reentrant_lock::ReentrantLockGuard; +pub use alloc_crate::sync::Arc; #[derive(Debug, PartialEq, Eq, Copy, Clone)] #[stable(feature = "wait_timeout", since = "1.5.0")] pub struct WaitTimeoutResult(bool); + +impl WaitTimeoutResult { + /// Returns `true` if the wait was known to have timed out. + /// + /// # Examples + /// + /// This example spawns a thread which will sleep 20 milliseconds before + /// updating a boolean value and then notifying the condvar. + /// + /// The main thread will wait with a 10 millisecond timeout on the condvar + /// and will leave the loop upon timeout. + /// + /// ``` + /// use std::sync::{Arc, Condvar, Mutex}; + /// use std::thread; + /// use std::time::Duration; + /// + /// let pair = Arc::new((Mutex::new(false), Condvar::new())); + /// let pair2 = Arc::clone(&pair); + /// + /// # let handle = + /// thread::spawn(move || { + /// let (lock, cvar) = &*pair2; + /// + /// // Let's wait 20 milliseconds before notifying the condvar. + /// thread::sleep(Duration::from_millis(20)); + /// + /// let mut started = lock.lock().unwrap(); + /// // We update the boolean value. + /// *started = true; + /// cvar.notify_one(); + /// }); + /// + /// // Wait for the thread to start up. + /// let (lock, cvar) = &*pair; + /// loop { + /// // Let's put a timeout on the condvar's wait. + /// let result = cvar.wait_timeout(lock.lock().unwrap(), Duration::from_millis(10)).unwrap(); + /// // 10 milliseconds have passed. + /// if result.1.timed_out() { + /// // timed out now and we can leave. + /// break + /// } + /// } + /// # // Prevent leaks for Miri. + /// # let _ = handle.join(); + /// ``` + #[must_use] + #[stable(feature = "wait_timeout", since = "1.5.0")] + pub fn timed_out(&self) -> bool { + self.0 + } +} diff --git a/crates/std/src/sync/barrier.rs b/crates/std/src/sync/barrier.rs index 5528b93..6a5cc9b 100644 --- a/crates/std/src/sync/barrier.rs +++ b/crates/std/src/sync/barrier.rs @@ -1,5 +1,5 @@ use crate::fmt; -use core::panic::RefUnwindSafe; +use crate::panic::RefUnwindSafe; use crate::sync::nonpoison::{Condvar, Mutex}; /// A barrier enables multiple threads to synchronize the beginning diff --git a/crates/std/src/sync/lazy_lock.rs b/crates/std/src/sync/lazy_lock.rs index 5030b4e..7274b5d 100644 --- a/crates/std/src/sync/lazy_lock.rs +++ b/crates/std/src/sync/lazy_lock.rs @@ -2,7 +2,7 @@ use super::once::OnceExclusiveState; use crate::cell::UnsafeCell; use crate::mem::ManuallyDrop; use crate::ops::{Deref, DerefMut}; -use core::panic::{RefUnwindSafe, UnwindSafe}; +use crate::panic::{RefUnwindSafe, UnwindSafe}; use crate::sync::Once; use crate::{fmt, ptr}; diff --git a/crates/std/src/sync/mpmc/mod.rs b/crates/std/src/sync/mpmc/mod.rs index 891f793..8df81a5 100644 --- a/crates/std/src/sync/mpmc/mod.rs +++ b/crates/std/src/sync/mpmc/mod.rs @@ -150,7 +150,7 @@ mod zero; pub use error::*; use crate::fmt; -use core::panic::{RefUnwindSafe, UnwindSafe}; +use crate::panic::{RefUnwindSafe, UnwindSafe}; use crate::time::{Duration, Instant}; /// Creates a new asynchronous channel, returning the sender/receiver halves. diff --git a/crates/std/src/sync/once.rs b/crates/std/src/sync/once.rs index 65ae0d9..bcfc9f5 100644 --- a/crates/std/src/sync/once.rs +++ b/crates/std/src/sync/once.rs @@ -4,7 +4,7 @@ //! example use case would be for initializing an FFI library. use crate::fmt; -use core::panic::{RefUnwindSafe, UnwindSafe}; +use crate::panic::{RefUnwindSafe, UnwindSafe}; use crate::sys::sync as sys; /// A low-level synchronization primitive for one-time global execution. diff --git a/crates/std/src/sync/once_lock.rs b/crates/std/src/sync/once_lock.rs index 44ab9f9..f6ea3c1 100644 --- a/crates/std/src/sync/once_lock.rs +++ b/crates/std/src/sync/once_lock.rs @@ -3,7 +3,7 @@ use crate::cell::UnsafeCell; use crate::fmt; use crate::marker::PhantomData; use crate::mem::MaybeUninit; -use core::panic::{RefUnwindSafe, UnwindSafe}; +use crate::panic::{RefUnwindSafe, UnwindSafe}; use crate::sync::Once; /// A synchronization primitive which can nominally be written to only once. diff --git a/crates/std/src/sync/poison/mutex.rs b/crates/std/src/sync/poison/mutex.rs index 882875b..6eccd8a 100644 --- a/crates/std/src/sync/poison/mutex.rs +++ b/crates/std/src/sync/poison/mutex.rs @@ -88,8 +88,8 @@ use crate::sys::sync as sys; /// [`unwrap()`]: Result::unwrap /// [`PoisonError`]: super::PoisonError /// [`into_inner`]: super::PoisonError::into_inner -/// [panic hook]: core::panic::set_hook -/// [`catch_unwind`]: core::panic::catch_unwind +/// [panic hook]: crate::panic::set_hook +/// [`catch_unwind`]: crate::panic::catch_unwind /// [`Cell`]: crate::cell::Cell /// /// # Examples diff --git a/crates/std/src/sync/reentrant_lock.rs b/crates/std/src/sync/reentrant_lock.rs index 5959a0a..f560b61 100644 --- a/crates/std/src/sync/reentrant_lock.rs +++ b/crates/std/src/sync/reentrant_lock.rs @@ -1,7 +1,7 @@ use crate::cell::UnsafeCell; use crate::fmt; use crate::ops::Deref; -use core::panic::{RefUnwindSafe, UnwindSafe}; +use crate::panic::{RefUnwindSafe, UnwindSafe}; use crate::sys::sync as sys; use crate::thread::{ThreadId, current_id}; diff --git a/crates/std/src/sys/backtrace.rs b/crates/std/src/sys/backtrace.rs new file mode 100644 index 0000000..4bf30c3 --- /dev/null +++ b/crates/std/src/sys/backtrace.rs @@ -0,0 +1,242 @@ +//! Common code for printing backtraces. +#![forbid(unsafe_op_in_unsafe_fn)] + +// use crate::backtrace_rs::{self, BacktraceFmt, BytesOrWideString, PrintFmt}; +use crate::borrow::Cow; +use crate::io::prelude::*; +use crate::path::{self, Path, PathBuf}; +use crate::sync::{Mutex, MutexGuard, PoisonError}; +use crate::{env, fmt, io}; + +/// Max number of frames to print. +const MAX_NB_FRAMES: usize = 100; + +pub(crate) const FULL_BACKTRACE_DEFAULT: bool = cfg_select! { + // Fuchsia components default to full backtrace. + target_os = "fuchsia" => true, + _ => false, +}; + +pub(crate) struct BacktraceLock<'a>(#[allow(dead_code)] MutexGuard<'a, ()>); + +pub(crate) fn lock<'a>() -> BacktraceLock<'a> { + static LOCK: Mutex<()> = Mutex::new(()); + BacktraceLock(LOCK.lock().unwrap_or_else(PoisonError::into_inner)) +} + +// impl BacktraceLock<'_> { +// /// Prints the current backtrace. +// pub(crate) fn print(&mut self, w: &mut dyn Write, format: PrintFmt) -> io::Result<()> { +// // There are issues currently linking libbacktrace into tests, and in +// // general during std's own unit tests we're not testing this path. In +// // test mode immediately return here to optimize away any references to the +// // libbacktrace symbols +// if cfg!(test) { +// return Ok(()); +// } + +// struct DisplayBacktrace { +// format: PrintFmt, +// } +// impl fmt::Display for DisplayBacktrace { +// fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { +// // SAFETY: the backtrace lock is held +// unsafe { _print_fmt(fmt, self.format) } +// } +// } +// write!(w, "{}", DisplayBacktrace { format }) +// } +// } + +// /// # Safety +// /// +// /// This function is not Sync. The caller must hold a mutex lock, or there must be only one thread in the program. +// unsafe fn _print_fmt(fmt: &mut fmt::Formatter<'_>, print_fmt: PrintFmt) -> fmt::Result { +// // Always 'fail' to get the cwd when running under Miri - +// // this allows Miri to display backtraces in isolation mode +// let cwd = if !cfg!(miri) { +// env::current_dir().ok() +// } else { +// None +// }; + +// let mut print_path = move |fmt: &mut fmt::Formatter<'_>, bows: BytesOrWideString<'_>| { +// output_filename(fmt, bows, print_fmt, cwd.as_ref()) +// }; +// writeln!(fmt, "stack backtrace:")?; +// let mut bt_fmt = BacktraceFmt::new(fmt, print_fmt, &mut print_path); +// bt_fmt.add_context()?; +// let mut idx = 0; +// let mut res = Ok(()); +// let mut omitted_count: usize = 0; +// let mut first_omit = true; +// // If we're using a short backtrace, ignore all frames until we're told to start printing. +// let mut print = print_fmt != PrintFmt::Short; +// set_image_base(); +// // SAFETY: we roll our own locking in this town +// unsafe { +// backtrace_rs::trace_unsynchronized(|frame| { +// if print_fmt == PrintFmt::Short && idx > MAX_NB_FRAMES { +// return false; +// } + +// if cfg!(feature = "backtrace-trace-only") { +// const HEX_WIDTH: usize = 2 + 2 * size_of::(); +// let frame_ip = frame.ip(); +// res = writeln!(bt_fmt.formatter(), "{idx:4}: {frame_ip:HEX_WIDTH$?}"); +// } else { +// let mut hit = false; +// backtrace_rs::resolve_frame_unsynchronized(frame, |symbol| { +// hit = true; + +// // `__rust_end_short_backtrace` means we are done hiding symbols +// // for now. Print until we see `__rust_begin_short_backtrace`. +// if print_fmt == PrintFmt::Short { +// if let Some(sym) = symbol.name().and_then(|s| s.as_str()) { +// if sym.contains("__rust_end_short_backtrace") { +// print = true; +// return; +// } +// if print && sym.contains("__rust_begin_short_backtrace") { +// print = false; +// return; +// } +// if !print { +// omitted_count += 1; +// } +// } +// } + +// if print { +// if omitted_count > 0 { +// debug_assert!(print_fmt == PrintFmt::Short); +// // only print the message between the middle of frames +// if !first_omit { +// let _ = writeln!( +// bt_fmt.formatter(), +// " [... omitted {} frame{} ...]", +// omitted_count, +// if omitted_count > 1 { "s" } else { "" } +// ); +// } +// first_omit = false; +// omitted_count = 0; +// } +// res = bt_fmt.frame().symbol(frame, symbol); +// } +// }); +// #[cfg(all(target_os = "nto", any(target_env = "nto70", target_env = "nto71")))] +// if libc::__my_thread_exit as *mut libc::c_void == frame.ip() { +// if !hit && print { +// use crate::backtrace_rs::SymbolName; +// res = bt_fmt.frame().print_raw( +// frame.ip(), +// Some(SymbolName::new("__my_thread_exit".as_bytes())), +// None, +// None, +// ); +// } +// return false; +// } +// if !hit && print { +// res = bt_fmt.frame().print_raw(frame.ip(), None, None, None); +// } +// } + +// idx += 1; +// res.is_ok() +// }) +// }; +// res?; +// bt_fmt.finish()?; +// if print_fmt == PrintFmt::Short { +// writeln!( +// fmt, +// "note: Some details are omitted, \ +// run with `RUST_BACKTRACE=full` for a verbose backtrace." +// )?; +// } +// Ok(()) +// } + +/// Fixed frame used to clean the backtrace with `RUST_BACKTRACE=1`. Note that +/// this is only inline(never) when backtraces in std are enabled, otherwise +/// it's fine to optimize away. +#[cfg_attr(feature = "backtrace", inline(never))] +pub fn __rust_begin_short_backtrace(f: F) -> T +where + F: FnOnce() -> T, +{ + let result = f(); + + // prevent this frame from being tail-call optimised away + crate::hint::black_box(()); + + result +} + +/// Fixed frame used to clean the backtrace with `RUST_BACKTRACE=1`. Note that +/// this is only inline(never) when backtraces in std are enabled, otherwise +/// it's fine to optimize away. +#[cfg_attr(feature = "backtrace", inline(never))] +pub fn __rust_end_short_backtrace(f: F) -> T +where + F: FnOnce() -> T, +{ + let result = f(); + + // prevent this frame from being tail-call optimised away + crate::hint::black_box(()); + + result +} + +// /// Prints the filename of the backtrace frame. +// /// +// /// See also `output`. +// pub fn output_filename( +// fmt: &mut fmt::Formatter<'_>, +// bows: BytesOrWideString<'_>, +// print_fmt: PrintFmt, +// cwd: Option<&PathBuf>, +// ) -> fmt::Result { +// let file: Cow<'_, Path> = match bows { +// #[cfg(unix)] +// BytesOrWideString::Bytes(bytes) => { +// use crate::os::unix::prelude::*; +// Path::new(crate::ffi::OsStr::from_bytes(bytes)).into() +// } +// #[cfg(not(unix))] +// BytesOrWideString::Bytes(bytes) => { +// Path::new(crate::str::from_utf8(bytes).unwrap_or("")).into() +// } +// #[cfg(windows)] +// BytesOrWideString::Wide(wide) => { +// use crate::os::windows::prelude::*; +// Cow::Owned(crate::ffi::OsString::from_wide(wide).into()) +// } +// #[cfg(not(windows))] +// BytesOrWideString::Wide(_wide) => Path::new("").into(), +// }; +// if print_fmt == PrintFmt::Short && file.is_absolute() { +// if let Some(cwd) = cwd { +// if let Ok(stripped) = file.strip_prefix(&cwd) { +// if let Some(s) = stripped.to_str() { +// return write!(fmt, ".{}{s}", path::MAIN_SEPARATOR); +// } +// } +// } +// } +// fmt::Display::fmt(&file.display(), fmt) +// } + +#[cfg(all(target_vendor = "fortanix", target_env = "sgx"))] +pub fn set_image_base() { + let image_base = crate::os::fortanix_sgx::mem::image_base(); + backtrace_rs::set_image_base(crate::ptr::without_provenance_mut(image_base as _)); +} + +#[cfg(not(all(target_vendor = "fortanix", target_env = "sgx")))] +pub fn set_image_base() { + // nothing to do for platforms other than SGX +} diff --git a/crates/std/src/sys/mod.rs b/crates/std/src/sys/mod.rs index 303738f..45ce3b4 100644 --- a/crates/std/src/sys/mod.rs +++ b/crates/std/src/sys/mod.rs @@ -14,6 +14,7 @@ pub mod alloc; pub mod io; pub mod pipe; pub mod stdio; +pub mod backtrace; // pub mod fs; /// A trait for viewing representations from std types. diff --git a/crates/std/src/sys/sync/mod.rs b/crates/std/src/sys/sync/mod.rs index 623e6bc..52fac59 100644 --- a/crates/std/src/sys/sync/mod.rs +++ b/crates/std/src/sys/sync/mod.rs @@ -2,8 +2,10 @@ mod condvar; mod mutex; mod once; mod rwlock; +mod thread_parking; pub use condvar::Condvar; pub use mutex::Mutex; pub use once::{Once, OnceState}; pub use rwlock::RwLock; +pub use thread_parking::Parker; diff --git a/crates/std/src/sys/sync/thread_parking/mod.rs b/crates/std/src/sys/sync/thread_parking/mod.rs new file mode 100644 index 0000000..74b5b72 --- /dev/null +++ b/crates/std/src/sys/sync/thread_parking/mod.rs @@ -0,0 +1,49 @@ +cfg_select! { + any( + all(target_os = "windows", not(target_vendor = "win7")), + target_os = "linux", + target_os = "android", + all(target_arch = "wasm32", target_feature = "atomics"), + target_os = "freebsd", + target_os = "openbsd", + target_os = "dragonfly", + target_os = "fuchsia", + target_os = "motor", + target_os = "hermit", + ) => { + mod futex; + pub use futex::Parker; + } + any( + target_os = "netbsd", + all(target_vendor = "fortanix", target_env = "sgx"), + target_os = "solid_asp3", + ) => { + mod id; + pub use id::Parker; + } + target_vendor = "win7" => { + mod windows7; + pub use windows7::Parker; + } + all(target_vendor = "apple", not(miri)) => { + // Doesn't work in Miri, see . + mod darwin; + pub use darwin::Parker; + } + target_os = "xous" => { + mod xous; + pub use xous::Parker; + } + any( + target_family = "unix", + target_os = "teeos", + ) => { + mod pthread; + pub use pthread::Parker; + } + _ => { + mod unsupported; + pub use unsupported::Parker; + } +} diff --git a/crates/std/src/sys/sync/thread_parking/unsupported.rs b/crates/std/src/sys/sync/thread_parking/unsupported.rs new file mode 100644 index 0000000..197078b --- /dev/null +++ b/crates/std/src/sys/sync/thread_parking/unsupported.rs @@ -0,0 +1,11 @@ +use crate::pin::Pin; +use crate::time::Duration; + +pub struct Parker {} + +impl Parker { + pub unsafe fn new_in_place(_parker: *mut Parker) {} + pub unsafe fn park(self: Pin<&Self>) {} + pub unsafe fn park_timeout(self: Pin<&Self>, _dur: Duration) {} + pub fn unpark(self: Pin<&Self>) {} +} diff --git a/crates/std/src/sys/thread_local/os.rs b/crates/std/src/sys/thread_local/os.rs index cbbe3a9..3f06c9b 100644 --- a/crates/std/src/sys/thread_local/os.rs +++ b/crates/std/src/sys/thread_local/os.rs @@ -5,7 +5,7 @@ use crate::cell::Cell; use crate::marker::PhantomData; use crate::mem::ManuallyDrop; use crate::ops::Deref; -use core::panic::{AssertUnwindSafe, catch_unwind, resume_unwind}; +use crate::panic::{AssertUnwindSafe, catch_unwind, resume_unwind}; use crate::ptr::{self, NonNull}; #[doc(hidden)] diff --git a/crates/std/src/thread.rs b/crates/std/src/thread.rs index f748abb..da581ad 100644 --- a/crates/std/src/thread.rs +++ b/crates/std/src/thread.rs @@ -6,18 +6,23 @@ pub mod join_handle; pub mod lifecycle; pub mod local; pub mod main_thread; +pub mod scoped; +pub mod spawnhook; pub mod thread; use core::any::Any; pub use crate::sys::thread::yield_now; -pub(crate) use current::current_or_unnamed; pub use current::current_id; +pub(crate) use current::current_or_unnamed; +pub(crate) use current::current_os_id; +pub(crate) use current::with_current_name; pub use functions::sleep; pub use id::ThreadId; +pub(crate) use lifecycle::ThreadInit; pub use local::LocalKey; pub use thread::Thread; -pub(crate) use lifecycle::ThreadInit; +pub use local::AccessError; // Implementation details used by the thread_local!{} macro. #[doc(hidden)] @@ -30,3 +35,7 @@ pub mod local_impl { #[stable(feature = "rust1", since = "1.0.0")] #[doc(search_unbox)] pub type Result = crate::result::Result>; + +pub fn panicking() -> ! { + todo!() +} diff --git a/crates/std/src/thread/functions.rs b/crates/std/src/thread/functions.rs index 23aceef..95d7aaf 100644 --- a/crates/std/src/thread/functions.rs +++ b/crates/std/src/thread/functions.rs @@ -7,7 +7,7 @@ use crate::mem::forget; use crate::num::NonZero; use crate::sys::thread as imp; use crate::time::{Duration, Instant}; -use crate::io;use core::panicking; +use crate::{io, panicking}; /// Spawns a new thread, returning a [`JoinHandle`] for it. /// diff --git a/crates/std/src/thread/lifecycle.rs b/crates/std/src/thread/lifecycle.rs index e0094a8..3a7e65f 100644 --- a/crates/std/src/thread/lifecycle.rs +++ b/crates/std/src/thread/lifecycle.rs @@ -11,7 +11,7 @@ use crate::mem::{ManuallyDrop, MaybeUninit}; use alloc_crate::sync::Arc; use crate::sync::atomic::{Atomic, AtomicUsize, Ordering}; use crate::sys::{AsInner, IntoInner, thread as imp}; -use crate::{env, io};use core::panic; +use crate::{env, io, panic}; #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub(super) unsafe fn spawn_unchecked<'scope, F, T>( diff --git a/crates/std/src/thread/scoped.rs b/crates/std/src/thread/scoped.rs new file mode 100644 index 0000000..6c7e0cb --- /dev/null +++ b/crates/std/src/thread/scoped.rs @@ -0,0 +1,358 @@ +use super::Result; +use super::builder::Builder; +use super::current::current_or_unnamed; +use super::lifecycle::{JoinInner, spawn_unchecked}; +use super::thread::Thread; +use crate::marker::PhantomData; +use crate::panic::{AssertUnwindSafe, catch_unwind, resume_unwind}; +use alloc_crate::sync::Arc; +use crate::sync::atomic::{Atomic, AtomicBool, AtomicUsize, Ordering}; +use crate::{fmt, io}; + +/// A scope to spawn scoped threads in. +/// +/// See [`scope`] for details. +#[stable(feature = "scoped_threads", since = "1.63.0")] +pub struct Scope<'scope, 'env: 'scope> { + data: Arc, + /// Invariance over 'scope, to make sure 'scope cannot shrink, + /// which is necessary for soundness. + /// + /// Without invariance, this would compile fine but be unsound: + /// + /// ```compile_fail,E0373 + /// std::thread::scope(|s| { + /// s.spawn(|| { + /// let a = String::from("abcd"); + /// s.spawn(|| println!("{a:?}")); // might run after `a` is dropped + /// }); + /// }); + /// ``` + scope: PhantomData<&'scope mut &'scope ()>, + env: PhantomData<&'env mut &'env ()>, +} + +/// An owned permission to join on a scoped thread (block on its termination). +/// +/// See [`Scope::spawn`] for details. +#[stable(feature = "scoped_threads", since = "1.63.0")] +pub struct ScopedJoinHandle<'scope, T>(JoinInner<'scope, T>); + +pub(super) struct ScopeData { + num_running_threads: Atomic, + a_thread_panicked: Atomic, + main_thread: Thread, +} + +impl ScopeData { + pub(super) fn increment_num_running_threads(&self) { + // We check for 'overflow' with usize::MAX / 2, to make sure there's no + // chance it overflows to 0, which would result in unsoundness. + if self.num_running_threads.fetch_add(1, Ordering::Relaxed) > usize::MAX / 2 { + // This can only reasonably happen by mem::forget()'ing a lot of ScopedJoinHandles. + self.overflow(); + } + } + + #[cold] + fn overflow(&self) { + self.decrement_num_running_threads(false); + panic!("too many running threads in thread scope"); + } + + pub(super) fn decrement_num_running_threads(&self, panic: bool) { + if panic { + self.a_thread_panicked.store(true, Ordering::Relaxed); + } + if self.num_running_threads.fetch_sub(1, Ordering::Release) == 1 { + self.main_thread.unpark(); + } + } +} + +/// Creates a scope for spawning scoped threads. +/// +/// The function passed to `scope` will be provided a [`Scope`] object, +/// through which scoped threads can be [spawned][`Scope::spawn`]. +/// +/// Unlike non-scoped threads, scoped threads can borrow non-`'static` data, +/// as the scope guarantees all threads will be joined at the end of the scope. +/// +/// All threads spawned within the scope that haven't been manually joined +/// will be automatically joined before this function returns. +/// However, note that joining will only wait for the main function of these threads to finish; even +/// when this function returns, destructors of thread-local variables in these threads might still +/// be running. +/// +/// # Panics +/// +/// If any of the automatically joined threads panicked, this function will panic. +/// +/// If you want to handle panics from spawned threads, +/// [`join`][ScopedJoinHandle::join] them before the end of the scope. +/// +/// # Example +/// +/// ``` +/// use std::thread; +/// +/// let mut a = vec![1, 2, 3]; +/// let mut x = 0; +/// +/// thread::scope(|s| { +/// s.spawn(|| { +/// println!("hello from the first scoped thread"); +/// // We can borrow `a` here. +/// dbg!(&a); +/// }); +/// s.spawn(|| { +/// println!("hello from the second scoped thread"); +/// // We can even mutably borrow `x` here, +/// // because no other threads are using it. +/// x += a[0] + a[2]; +/// }); +/// println!("hello from the main thread"); +/// }); +/// +/// // After the scope, we can modify and access our variables again: +/// a.push(4); +/// assert_eq!(x, a.len()); +/// ``` +/// +/// # Lifetimes +/// +/// Scoped threads involve two lifetimes: `'scope` and `'env`. +/// +/// The `'scope` lifetime represents the lifetime of the scope itself. +/// That is: the time during which new scoped threads may be spawned, +/// and also the time during which they might still be running. +/// Once this lifetime ends, all scoped threads are joined. +/// This lifetime starts within the `scope` function, before `f` (the argument to `scope`) starts. +/// It ends after `f` returns and all scoped threads have been joined, but before `scope` returns. +/// +/// The `'env` lifetime represents the lifetime of whatever is borrowed by the scoped threads. +/// This lifetime must outlast the call to `scope`, and thus cannot be smaller than `'scope`. +/// It can be as small as the call to `scope`, meaning that anything that outlives this call, +/// such as local variables defined right before the scope, can be borrowed by the scoped threads. +/// +/// The `'env: 'scope` bound is part of the definition of the `Scope` type. +#[track_caller] +#[stable(feature = "scoped_threads", since = "1.63.0")] +pub fn scope<'env, F, T>(f: F) -> T +where + F: for<'scope> FnOnce(&'scope Scope<'scope, 'env>) -> T, +{ + // We put the `ScopeData` into an `Arc` so that other threads can finish their + // `decrement_num_running_threads` even after this function returns. + let scope = Scope { + data: Arc::new(ScopeData { + num_running_threads: AtomicUsize::new(0), + main_thread: current_or_unnamed(), + a_thread_panicked: AtomicBool::new(false), + }), + env: PhantomData, + scope: PhantomData, + }; + + // Run `f`, but catch panics so we can make sure to wait for all the threads to join. + let result = catch_unwind(AssertUnwindSafe(|| f(&scope))); + + // Wait until all the threads are finished. + while scope.data.num_running_threads.load(Ordering::Acquire) != 0 { + // SAFETY: this is the main thread, the handle belongs to us. + unsafe { scope.data.main_thread.park() }; + } + + // Throw any panic from `f`, or the return value of `f` if no thread panicked. + match result { + Err(e) => resume_unwind(e), + Ok(_) if scope.data.a_thread_panicked.load(Ordering::Relaxed) => { + panic!("a scoped thread panicked") + } + Ok(result) => result, + } +} + +impl<'scope, 'env> Scope<'scope, 'env> { + /// Spawns a new thread within a scope, returning a [`ScopedJoinHandle`] for it. + /// + /// Unlike non-scoped threads, threads spawned with this function may + /// borrow non-`'static` data from the outside the scope. See [`scope`] for + /// details. + /// + /// The join handle provides a [`join`] method that can be used to join the spawned + /// thread. If the spawned thread panics, [`join`] will return an [`Err`] containing + /// the panic payload. + /// + /// If the join handle is dropped, the spawned thread will be implicitly joined at the + /// end of the scope. In that case, if the spawned thread panics, [`scope`] will + /// panic after all threads are joined. + /// + /// This function creates a thread with the default parameters of [`Builder`]. + /// To specify the new thread's stack size or the name, use [`Builder::spawn_scoped`]. + /// + /// # Panics + /// + /// Panics if the OS fails to create a thread; use [`Builder::spawn_scoped`] + /// to recover from such errors. + /// + /// [`join`]: ScopedJoinHandle::join + #[stable(feature = "scoped_threads", since = "1.63.0")] + pub fn spawn(&'scope self, f: F) -> ScopedJoinHandle<'scope, T> + where + F: FnOnce() -> T + Send + 'scope, + T: Send + 'scope, + { + Builder::new().spawn_scoped(self, f).expect("failed to spawn thread") + } +} + +impl Builder { + /// Spawns a new scoped thread using the settings set through this `Builder`. + /// + /// Unlike [`Scope::spawn`], this method yields an [`io::Result`] to + /// capture any failure to create the thread at the OS level. + /// + /// # Panics + /// + /// Panics if a thread name was set and it contained null bytes. + /// + /// # Example + /// + /// ``` + /// use std::thread; + /// + /// let mut a = vec![1, 2, 3]; + /// let mut x = 0; + /// + /// thread::scope(|s| { + /// thread::Builder::new() + /// .name("first".to_string()) + /// .spawn_scoped(s, || + /// { + /// println!("hello from the {:?} scoped thread", thread::current().name()); + /// // We can borrow `a` here. + /// dbg!(&a); + /// }) + /// .unwrap(); + /// thread::Builder::new() + /// .name("second".to_string()) + /// .spawn_scoped(s, || + /// { + /// println!("hello from the {:?} scoped thread", thread::current().name()); + /// // We can even mutably borrow `x` here, + /// // because no other threads are using it. + /// x += a[0] + a[2]; + /// }) + /// .unwrap(); + /// println!("hello from the main thread"); + /// }); + /// + /// // After the scope, we can modify and access our variables again: + /// a.push(4); + /// assert_eq!(x, a.len()); + /// ``` + #[stable(feature = "scoped_threads", since = "1.63.0")] + pub fn spawn_scoped<'scope, 'env, F, T>( + self, + scope: &'scope Scope<'scope, 'env>, + f: F, + ) -> io::Result> + where + F: FnOnce() -> T + Send + 'scope, + T: Send + 'scope, + { + let Builder { name, stack_size, no_hooks } = self; + Ok(ScopedJoinHandle(unsafe { + spawn_unchecked(name, stack_size, no_hooks, Some(scope.data.clone()), f) + }?)) + } +} + +impl<'scope, T> ScopedJoinHandle<'scope, T> { + /// Extracts a handle to the underlying thread. + /// + /// # Examples + /// + /// ``` + /// use std::thread; + /// + /// thread::scope(|s| { + /// let t = s.spawn(|| { + /// println!("hello"); + /// }); + /// println!("thread id: {:?}", t.thread().id()); + /// }); + /// ``` + #[must_use] + #[stable(feature = "scoped_threads", since = "1.63.0")] + pub fn thread(&self) -> &Thread { + self.0.thread() + } + + /// Waits for the associated thread to finish. + /// + /// This function will return immediately if the associated thread has already finished. + /// Otherwise, it fully waits for the thread to finish, including all destructors + /// for thread-local variables that might be running after the main function of the thread. + /// + /// In terms of [atomic memory orderings], the completion of the associated + /// thread synchronizes with this function returning. + /// In other words, all operations performed by that thread + /// [happen before](https://doc.rust-lang.org/nomicon/atomics.html#data-accesses) + /// all operations that happen after `join` returns. + /// + /// If the associated thread panics, [`Err`] is returned with the panic payload. + /// + /// [atomic memory orderings]: crate::sync::atomic + /// + /// # Examples + /// + /// ``` + /// use std::thread; + /// + /// thread::scope(|s| { + /// let t = s.spawn(|| { + /// panic!("oh no"); + /// }); + /// assert!(t.join().is_err()); + /// }); + /// ``` + #[stable(feature = "scoped_threads", since = "1.63.0")] + pub fn join(self) -> Result { + self.0.join() + } + + /// Checks if the associated thread has finished running its main function. + /// + /// `is_finished` supports implementing a non-blocking join operation, by checking + /// `is_finished`, and calling `join` if it returns `true`. This function does not block. To + /// block while waiting on the thread to finish, use [`join`][Self::join]. + /// + /// This might return `true` for a brief moment after the thread's main + /// function has returned, but before the thread itself has stopped running. + /// However, once this returns `true`, [`join`][Self::join] can be expected + /// to return quickly, without blocking for any significant amount of time. + #[stable(feature = "scoped_threads", since = "1.63.0")] + pub fn is_finished(&self) -> bool { + self.0.is_finished() + } +} + +#[stable(feature = "scoped_threads", since = "1.63.0")] +impl fmt::Debug for Scope<'_, '_> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("Scope") + .field("num_running_threads", &self.data.num_running_threads.load(Ordering::Relaxed)) + .field("a_thread_panicked", &self.data.a_thread_panicked.load(Ordering::Relaxed)) + .field("main_thread", &self.data.main_thread) + .finish_non_exhaustive() + } +} + +#[stable(feature = "scoped_threads", since = "1.63.0")] +impl<'scope, T> fmt::Debug for ScopedJoinHandle<'scope, T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("ScopedJoinHandle").finish_non_exhaustive() + } +} diff --git a/crates/std/src/thread/spawnhook.rs b/crates/std/src/thread/spawnhook.rs new file mode 100644 index 0000000..a4a03e7 --- /dev/null +++ b/crates/std/src/thread/spawnhook.rs @@ -0,0 +1,153 @@ +use super::thread::Thread; +use crate::cell::Cell; +use crate::iter; +use alloc_crate::sync::Arc; + +crate::thread_local! { + /// A thread local linked list of spawn hooks. + /// + /// It is a linked list of Arcs, such that it can very cheaply be inherited by spawned threads. + /// + /// (That technically makes it a set of linked lists with shared tails, so a linked tree.) + static SPAWN_HOOKS: Cell = const { Cell::new(SpawnHooks { first: None }) }; +} + +#[derive(Default, Clone)] +struct SpawnHooks { + first: Option>, +} + +// Manually implement drop to prevent deep recursion when dropping linked Arc list. +impl Drop for SpawnHooks { + fn drop(&mut self) { + let mut next = self.first.take(); + while let Some(SpawnHook { hook, next: n }) = next.and_then(|n| Arc::into_inner(n)) { + drop(hook); + next = n; + } + } +} + +struct SpawnHook { + hook: Box Box>, + next: Option>, +} + +/// Registers a function to run for every newly thread spawned. +/// +/// The hook is executed in the parent thread, and returns a function +/// that will be executed in the new thread. +/// +/// The hook is called with the `Thread` handle for the new thread. +/// +/// The hook will only be added for the current thread and is inherited by the threads it spawns. +/// In other words, adding a hook has no effect on already running threads (other than the current +/// thread) and the threads they might spawn in the future. +/// +/// Hooks can only be added, not removed. +/// +/// The hooks will run in reverse order, starting with the most recently added. +/// +/// # Usage +/// +/// ``` +/// #![feature(thread_spawn_hook)] +/// +/// std::thread::add_spawn_hook(|_| { +/// ..; // This will run in the parent (spawning) thread. +/// move || { +/// ..; // This will run it the child (spawned) thread. +/// } +/// }); +/// ``` +/// +/// # Example +/// +/// A spawn hook can be used to "inherit" a thread local from the parent thread: +/// +/// ``` +/// #![feature(thread_spawn_hook)] +/// +/// use std::cell::Cell; +/// +/// thread_local! { +/// static X: Cell = Cell::new(0); +/// } +/// +/// // This needs to be done once in the main thread before spawning any threads. +/// std::thread::add_spawn_hook(|_| { +/// // Get the value of X in the spawning thread. +/// let value = X.get(); +/// // Set the value of X in the newly spawned thread. +/// move || X.set(value) +/// }); +/// +/// X.set(123); +/// +/// std::thread::spawn(|| { +/// assert_eq!(X.get(), 123); +/// }).join().unwrap(); +/// ``` +#[unstable(feature = "thread_spawn_hook", issue = "132951")] +pub fn add_spawn_hook(hook: F) +where + F: 'static + Send + Sync + Fn(&Thread) -> G, + G: 'static + Send + FnOnce(), +{ + SPAWN_HOOKS.with(|h| { + let mut hooks = h.take(); + let next = hooks.first.take(); + hooks.first = Some(Arc::new(SpawnHook { + hook: Box::new(move |thread| Box::new(hook(thread))), + next, + })); + h.set(hooks); + }); +} + +/// Runs all the spawn hooks. +/// +/// Called on the parent thread. +/// +/// Returns the functions to be called on the newly spawned thread. +pub(super) fn run_spawn_hooks(thread: &Thread) -> ChildSpawnHooks { + // Get a snapshot of the spawn hooks. + // (Increments the refcount to the first node.) + if let Ok(hooks) = SPAWN_HOOKS.try_with(|hooks| { + let snapshot = hooks.take(); + hooks.set(snapshot.clone()); + snapshot + }) { + // Iterate over the hooks, run them, and collect the results in a vector. + let to_run: Vec<_> = iter::successors(hooks.first.as_deref(), |hook| hook.next.as_deref()) + .map(|hook| (hook.hook)(thread)) + .collect(); + // Pass on the snapshot of the hooks and the results to the new thread, + // which will then run SpawnHookResults::run(). + ChildSpawnHooks { hooks, to_run } + } else { + // TLS has been destroyed. Skip running the hooks. + // See https://github.com/rust-lang/rust/issues/138696 + ChildSpawnHooks::default() + } +} + +/// The results of running the spawn hooks. +/// +/// This struct is sent to the new thread. +/// It contains the inherited hooks and the closures to be run. +#[derive(Default)] +pub(super) struct ChildSpawnHooks { + hooks: SpawnHooks, + to_run: Vec>, +} + +impl ChildSpawnHooks { + // This is run on the newly spawned thread, directly at the start. + pub(super) fn run(self) { + SPAWN_HOOKS.set(self.hooks); + for run in self.to_run { + run(); + } + } +} diff --git a/justfile b/justfile index 117f886..48bf23d 100644 --- a/justfile +++ b/justfile @@ -28,6 +28,12 @@ update_std: # @just cp_std "fs.rs" @just cp_std "time.rs" @just cp_std "bstr.rs" + @just cp_std "panicking.rs" + @just cp_std "panic.rs" + @just cp_std "collections/hash/map.rs" + @just cp_std "collections/hash/set.rs" + @just cp_std "collections/hash/mod.rs" + @just cp_std "collections/mod.rs" @just cp_std "io/error.rs" @just cp_std "io/error/repr_bitpacked.rs" @just cp_std "io/error/repr_unpacked.rs" @@ -44,7 +50,7 @@ update_std: @just cp_std "io/copy/tests.rs" @just cp_std "io/pipe.rs" @just cp_std "io/pipe/tests.rs" - @just cp_std "io/stdio.rs" + # @just cp_std "io/stdio.rs" @just cp_std "io/buffered/mod.rs" @just cp_std "io/buffered/bufreader.rs" @just cp_std "io/buffered/bufreader/buffer.rs" @@ -92,6 +98,8 @@ update_std: @just cp_std "thread/functions.rs" @just cp_std "thread/lifecycle.rs" @just cp_std "thread/builder.rs" + @just cp_std "thread/scoped.rs" + @just cp_std "thread/spawnhook.rs" @just cp_std "sys/exit.rs" @just cp_std "sys/env_consts.rs" @just cp_std "sys/configure_builtins.rs" @@ -104,6 +112,8 @@ update_std: @just cp_std "sys/sync/once/no_threads.rs" @just cp_std "sys/sync/rwlock/mod.rs" @just cp_std "sys/sync/rwlock/no_threads.rs" + @just cp_std "sys/sync/thread_parking/mod.rs" + @just cp_std "sys/sync/thread_parking/unsupported.rs" @just cp_std "sys/thread/mod.rs" @just cp_std "sys/thread/unsupported.rs" @just cp_std "sys/thread_local/no_threads.rs" diff --git a/patches.sed b/patches.sed index f1bd33f..110f8a0 100644 --- a/patches.sed +++ b/patches.sed @@ -5,9 +5,8 @@ s|alloc::slice::Join|alloc_crate::slice::Join|g s|alloc::bstr|alloc_crate::bstr|g s|alloc::collections::TryReserveError|alloc_crate::collections::TryReserveError|g s|crate::collections::VecDeque|alloc_crate::collections::VecDeque|g -s|crate::panic|core::panic|g -s|use crate::{io, panicking};|use crate::io;use core::panicking;|g -s|use crate::{env, io, panic};|use crate::{env, io};use core::panic;|g +# s|collections::HashMap|hashbrown::HashMap|g +/crate::backtrace_rs/c \ todo!() # /target_os = "xous",/a \ target_os = "survos", # Ajouter d'autres modifications facilement ici :