diff options
Diffstat (limited to 'library')
396 files changed, 15915 insertions, 7933 deletions
diff --git a/library/alloc/Cargo.toml b/library/alloc/Cargo.toml index 5793f5e681b..b3ff0fd0a31 100644 --- a/library/alloc/Cargo.toml +++ b/library/alloc/Cargo.toml @@ -1,5 +1,4 @@ [package] -authors = ["The Rust Project Developers"] name = "alloc" version = "0.0.0" license = "MIT OR Apache-2.0" diff --git a/library/alloc/benches/binary_heap.rs b/library/alloc/benches/binary_heap.rs index 5b6538ea6c6..491243e22c7 100644 --- a/library/alloc/benches/binary_heap.rs +++ b/library/alloc/benches/binary_heap.rs @@ -36,7 +36,7 @@ fn bench_peek_mut_deref_mut(b: &mut Bencher) { let mut peek_mut = bheap.peek_mut().unwrap(); // The compiler shouldn't be able to optimize away the `sift_down` // assignment in `PeekMut`'s `DerefMut` implementation since - // the loop may not run. + // the loop might not run. for &i in vec.iter() { *peek_mut = i; } diff --git a/library/alloc/benches/btree/map.rs b/library/alloc/benches/btree/map.rs index 21a0fb844e8..920a5ca7db0 100644 --- a/library/alloc/benches/btree/map.rs +++ b/library/alloc/benches/btree/map.rs @@ -177,7 +177,7 @@ pub fn iteration_mut_100000(b: &mut Bencher) { bench_iteration_mut(b, 100000); } -fn bench_first_and_last(b: &mut Bencher, size: i32) { +fn bench_first_and_last_nightly(b: &mut Bencher, size: i32) { let map: BTreeMap<_, _> = (0..size).map(|i| (i, i)).collect(); b.iter(|| { for _ in 0..10 { @@ -187,19 +187,44 @@ fn bench_first_and_last(b: &mut Bencher, size: i32) { }); } +fn bench_first_and_last_stable(b: &mut Bencher, size: i32) { + let map: BTreeMap<_, _> = (0..size).map(|i| (i, i)).collect(); + b.iter(|| { + for _ in 0..10 { + black_box(map.iter().next()); + black_box(map.iter().next_back()); + } + }); +} + +#[bench] +pub fn first_and_last_0_nightly(b: &mut Bencher) { + bench_first_and_last_nightly(b, 0); +} + +#[bench] +pub fn first_and_last_0_stable(b: &mut Bencher) { + bench_first_and_last_stable(b, 0); +} + +#[bench] +pub fn first_and_last_100_nightly(b: &mut Bencher) { + bench_first_and_last_nightly(b, 100); +} + #[bench] -pub fn first_and_last_0(b: &mut Bencher) { - bench_first_and_last(b, 0); +pub fn first_and_last_100_stable(b: &mut Bencher) { + bench_first_and_last_stable(b, 100); } #[bench] -pub fn first_and_last_100(b: &mut Bencher) { - bench_first_and_last(b, 100); +pub fn first_and_last_10k_nightly(b: &mut Bencher) { + bench_first_and_last_nightly(b, 10_000); } #[bench] -pub fn first_and_last_10k(b: &mut Bencher) { - bench_first_and_last(b, 10_000); +pub fn first_and_last_10k_stable(b: &mut Bencher) { + bench_first_and_last_stable(b, 10_000); } const BENCH_RANGE_SIZE: i32 = 145; diff --git a/library/alloc/benches/vec.rs b/library/alloc/benches/vec.rs index 91eec10d575..c93a493cadb 100644 --- a/library/alloc/benches/vec.rs +++ b/library/alloc/benches/vec.rs @@ -726,3 +726,9 @@ fn bench_dedup_old_100000(b: &mut Bencher) { fn bench_dedup_new_100000(b: &mut Bencher) { bench_vec_dedup_new(b, 100000); } + +#[bench] +fn bench_flat_map_collect(b: &mut Bencher) { + let v = vec![777u32; 500000]; + b.iter(|| v.iter().flat_map(|color| color.rotate_left(8).to_be_bytes()).collect::<Vec<_>>()); +} diff --git a/library/alloc/src/borrow.rs b/library/alloc/src/borrow.rs index 9d61b3684b8..482a497201d 100644 --- a/library/alloc/src/borrow.rs +++ b/library/alloc/src/borrow.rs @@ -177,6 +177,7 @@ where /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr(not(test), rustc_diagnostic_item = "Cow")] pub enum Cow<'a, B: ?Sized + 'a> where B: ToOwned, diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs index eb91af8c61c..72216852376 100644 --- a/library/alloc/src/boxed.rs +++ b/library/alloc/src/boxed.rs @@ -157,7 +157,6 @@ use crate::alloc::{handle_alloc_error, WriteCloneIntoRaw}; use crate::alloc::{AllocError, Allocator, Global, Layout}; #[cfg(not(no_global_oom_handling))] use crate::borrow::Cow; -#[cfg(not(no_global_oom_handling))] use crate::raw_vec::RawVec; #[cfg(not(no_global_oom_handling))] use crate::str::from_boxed_utf8_unchecked; @@ -187,8 +186,6 @@ impl<T> Box<T> { /// ``` #[cfg(not(no_global_oom_handling))] #[inline(always)] - #[doc(alias = "alloc")] - #[doc(alias = "malloc")] #[stable(feature = "rust1", since = "1.0.0")] pub fn new(x: T) -> Self { box x @@ -239,7 +236,6 @@ impl<T> Box<T> { /// [zeroed]: mem::MaybeUninit::zeroed #[cfg(not(no_global_oom_handling))] #[inline] - #[doc(alias = "calloc")] #[unstable(feature = "new_uninit", issue = "63291")] pub fn new_zeroed() -> Box<mem::MaybeUninit<T>> { Self::new_zeroed_in(Global) @@ -592,6 +588,71 @@ impl<T> Box<[T]> { pub fn new_zeroed_slice(len: usize) -> Box<[mem::MaybeUninit<T>]> { unsafe { RawVec::with_capacity_zeroed(len).into_box(len) } } + + /// Constructs a new boxed slice with uninitialized contents. Returns an error if + /// the allocation fails + /// + /// # Examples + /// + /// ``` + /// #![feature(allocator_api, new_uninit)] + /// + /// let mut values = Box::<[u32]>::try_new_uninit_slice(3)?; + /// let values = unsafe { + /// // Deferred initialization: + /// values[0].as_mut_ptr().write(1); + /// values[1].as_mut_ptr().write(2); + /// values[2].as_mut_ptr().write(3); + /// values.assume_init() + /// }; + /// + /// assert_eq!(*values, [1, 2, 3]); + /// # Ok::<(), std::alloc::AllocError>(()) + /// ``` + #[unstable(feature = "allocator_api", issue = "32838")] + #[inline] + pub fn try_new_uninit_slice(len: usize) -> Result<Box<[mem::MaybeUninit<T>]>, AllocError> { + unsafe { + let layout = match Layout::array::<mem::MaybeUninit<T>>(len) { + Ok(l) => l, + Err(_) => return Err(AllocError), + }; + let ptr = Global.allocate(layout)?; + Ok(RawVec::from_raw_parts_in(ptr.as_mut_ptr() as *mut _, len, Global).into_box(len)) + } + } + + /// Constructs a new boxed slice with uninitialized contents, with the memory + /// being filled with `0` bytes. Returns an error if the allocation fails + /// + /// See [`MaybeUninit::zeroed`][zeroed] for examples of correct and incorrect usage + /// of this method. + /// + /// # Examples + /// + /// ``` + /// #![feature(allocator_api, new_uninit)] + /// + /// let values = Box::<[u32]>::try_new_zeroed_slice(3)?; + /// let values = unsafe { values.assume_init() }; + /// + /// assert_eq!(*values, [0, 0, 0]); + /// # Ok::<(), std::alloc::AllocError>(()) + /// ``` + /// + /// [zeroed]: mem::MaybeUninit::zeroed + #[unstable(feature = "allocator_api", issue = "32838")] + #[inline] + pub fn try_new_zeroed_slice(len: usize) -> Result<Box<[mem::MaybeUninit<T>]>, AllocError> { + unsafe { + let layout = match Layout::array::<mem::MaybeUninit<T>>(len) { + Ok(l) => l, + Err(_) => return Err(AllocError), + }; + let ptr = Global.allocate_zeroed(layout)?; + Ok(RawVec::from_raw_parts_in(ptr.as_mut_ptr() as *mut _, len, Global).into_box(len)) + } + } } impl<T, A: Allocator> Box<[T], A> { @@ -1209,7 +1270,7 @@ impl<T: ?Sized + Hasher, A: Allocator> Hasher for Box<T, A> { #[cfg(not(no_global_oom_handling))] #[stable(feature = "from_for_ptrs", since = "1.6.0")] impl<T> From<T> for Box<T> { - /// Converts a generic type `T` into a `Box<T>` + /// Converts a `T` into a `Box<T>` /// /// The conversion allocates on the heap and moves `t` /// from the stack into it. diff --git a/library/alloc/src/collections/binary_heap.rs b/library/alloc/src/collections/binary_heap.rs index 544e18d1ff3..fb340734e0b 100644 --- a/library/alloc/src/collections/binary_heap.rs +++ b/library/alloc/src/collections/binary_heap.rs @@ -209,6 +209,14 @@ use super::SpecExtend; /// assert!(heap.is_empty()) /// ``` /// +/// A `BinaryHeap` with a known list of items can be initialized from an array: +/// +/// ``` +/// use std::collections::BinaryHeap; +/// +/// let heap = BinaryHeap::from([1, 5, 2]); +/// ``` +/// /// ## Min-heap /// /// Either `std::cmp::Reverse` or a custom `Ord` implementation can be used to @@ -965,7 +973,6 @@ impl<T> BinaryHeap<T> { /// # Examples /// /// ``` - /// #![feature(shrink_to)] /// use std::collections::BinaryHeap; /// let mut heap: BinaryHeap<i32> = BinaryHeap::with_capacity(100); /// @@ -974,7 +981,7 @@ impl<T> BinaryHeap<T> { /// assert!(heap.capacity() >= 10); /// ``` #[inline] - #[unstable(feature = "shrink_to", reason = "new API", issue = "56431")] + #[stable(feature = "shrink_to", since = "1.56.0")] pub fn shrink_to(&mut self, min_capacity: usize) { self.data.shrink_to(min_capacity) } @@ -1034,7 +1041,6 @@ impl<T> BinaryHeap<T> { /// /// assert_eq!(heap.len(), 2); /// ``` - #[doc(alias = "length")] #[stable(feature = "rust1", since = "1.0.0")] pub fn len(&self) -> usize { self.data.len() @@ -1466,6 +1472,22 @@ impl<T: Ord> From<Vec<T>> for BinaryHeap<T> { } } +#[stable(feature = "std_collections_from_array", since = "1.56.0")] +impl<T: Ord, const N: usize> From<[T; N]> for BinaryHeap<T> { + /// ``` + /// use std::collections::BinaryHeap; + /// + /// let mut h1 = BinaryHeap::from([1, 4, 2, 3]); + /// let mut h2: BinaryHeap<_> = [1, 4, 2, 3].into(); + /// while let Some((a, b)) = h1.pop().zip(h2.pop()) { + /// assert_eq!(a, b); + /// } + /// ``` + fn from(arr: [T; N]) -> Self { + core::array::IntoIter::new(arr).collect() + } +} + #[stable(feature = "binary_heap_extras_15", since = "1.5.0")] impl<T> From<BinaryHeap<T>> for Vec<T> { /// Converts a `BinaryHeap<T>` into a `Vec<T>`. diff --git a/library/alloc/src/collections/btree/fix.rs b/library/alloc/src/collections/btree/fix.rs index af87a9b956a..c4861817dd0 100644 --- a/library/alloc/src/collections/btree/fix.rs +++ b/library/alloc/src/collections/btree/fix.rs @@ -3,7 +3,7 @@ use super::node::{marker, ForceResult::*, Handle, LeftOrRight::*, NodeRef, Root} impl<'a, K: 'a, V: 'a> NodeRef<marker::Mut<'a>, K, V, marker::LeafOrInternal> { /// Stocks up a possibly underfull node by merging with or stealing from a - /// sibling. If succesful but at the cost of shrinking the parent node, + /// sibling. If successful but at the cost of shrinking the parent node, /// returns that shrunk parent node. Returns an `Err` if the node is /// an empty root. fn fix_node_through_parent( diff --git a/library/alloc/src/collections/btree/map.rs b/library/alloc/src/collections/btree/map.rs index 30194aa446f..4b649e43371 100644 --- a/library/alloc/src/collections/btree/map.rs +++ b/library/alloc/src/collections/btree/map.rs @@ -9,7 +9,7 @@ use core::ops::{Index, RangeBounds}; use core::ptr; use super::borrow::DormantMutRef; -use super::navigate::LeafRange; +use super::navigate::{LazyLeafRange, LeafRange}; use super::node::{self, marker, ForceResult::*, Handle, NodeRef, Root}; use super::search::SearchResult::*; @@ -109,7 +109,20 @@ pub(super) const MIN_LEN: usize = node::MIN_LEN_AFTER_SPLIT; /// } /// ``` /// -/// `BTreeMap` also implements an [`Entry API`], which allows for more complex +/// A `BTreeMap` with a known list of items can be initialized from an array: +/// +/// ``` +/// use std::collections::BTreeMap; +/// +/// let solar_distance = BTreeMap::from([ +/// ("Mercury", 0.4), +/// ("Venus", 0.7), +/// ("Earth", 1.0), +/// ("Mars", 1.5), +/// ]); +/// ``` +/// +/// `BTreeMap` implements an [`Entry API`], which allows for complex /// methods of getting, setting, updating and removing keys and their values: /// /// [`Entry API`]: BTreeMap::entry @@ -148,9 +161,7 @@ pub struct BTreeMap<K, V> { #[stable(feature = "btree_drop", since = "1.7.0")] unsafe impl<#[may_dangle] K, #[may_dangle] V> Drop for BTreeMap<K, V> { fn drop(&mut self) { - if let Some(root) = self.root.take() { - Dropper { front: root.into_dying().first_leaf_edge(), remaining_length: self.length }; - } + drop(unsafe { ptr::read(self) }.into_iter()) } } @@ -278,7 +289,7 @@ where /// [`iter`]: BTreeMap::iter #[stable(feature = "rust1", since = "1.0.0")] pub struct Iter<'a, K: 'a, V: 'a> { - range: Range<'a, K, V>, + range: LazyLeafRange<marker::Immut<'a>, K, V>, length: usize, } @@ -296,10 +307,20 @@ impl<K: fmt::Debug, V: fmt::Debug> fmt::Debug for Iter<'_, K, V> { /// /// [`iter_mut`]: BTreeMap::iter_mut #[stable(feature = "rust1", since = "1.0.0")] -#[derive(Debug)] pub struct IterMut<'a, K: 'a, V: 'a> { - range: RangeMut<'a, K, V>, + range: LazyLeafRange<marker::ValMut<'a>, K, V>, length: usize, + + // Be invariant in `K` and `V` + _marker: PhantomData<&'a mut (K, V)>, +} + +#[stable(feature = "collection_debug", since = "1.17.0")] +impl<K: fmt::Debug, V: fmt::Debug> fmt::Debug for IterMut<'_, K, V> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let range = Iter { range: self.range.reborrow(), length: self.length }; + f.debug_list().entries(range).finish() + } } /// An owning iterator over the entries of a `BTreeMap`. @@ -310,7 +331,7 @@ pub struct IterMut<'a, K: 'a, V: 'a> { /// [`into_iter`]: IntoIterator::into_iter #[stable(feature = "rust1", since = "1.0.0")] pub struct IntoIter<K, V> { - range: LeafRange<marker::Dying, K, V>, + range: LazyLeafRange<marker::Dying, K, V>, length: usize, } @@ -318,8 +339,7 @@ impl<K, V> IntoIter<K, V> { /// Returns an iterator of references over the remaining items. #[inline] pub(super) fn iter(&self) -> Iter<'_, K, V> { - let range = Range { inner: self.range.reborrow() }; - Iter { range: range, length: self.length } + Iter { range: self.range.reborrow(), length: self.length } } } @@ -330,14 +350,6 @@ impl<K: fmt::Debug, V: fmt::Debug> fmt::Debug for IntoIter<K, V> { } } -/// A simplified version of `IntoIter` that is not double-ended and has only one -/// purpose: to drop the remainder of an `IntoIter`. Therefore it also serves to -/// drop an entire tree without the need to first look up a `back` leaf edge. -struct Dropper<K, V> { - front: Handle<NodeRef<marker::Dying, K, V, marker::Leaf>, marker::Edge>, - remaining_length: usize, -} - /// An iterator over the keys of a `BTreeMap`. /// /// This `struct` is created by the [`keys`] method on [`BTreeMap`]. See its @@ -889,7 +901,6 @@ impl<K, V> BTreeMap<K, V> { /// assert_eq!(map.remove(&1), Some("a")); /// assert_eq!(map.remove(&1), None); /// ``` - #[doc(alias = "delete")] #[stable(feature = "rust1", since = "1.0.0")] pub fn remove<Q: ?Sized>(&mut self, key: &Q) -> Option<V> where @@ -936,6 +947,7 @@ impl<K, V> BTreeMap<K, V> { /// Retains only the elements specified by the predicate. /// /// In other words, remove all pairs `(k, v)` such that `f(&k, &mut v)` returns `false`. + /// The elements are visited in ascending key order. /// /// # Examples /// @@ -1415,7 +1427,7 @@ 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 { range: self.range.iter(), length: self.length } + Iter { range: self.range.reborrow(), length: self.length } } } @@ -1431,52 +1443,62 @@ impl<K, V> IntoIterator for BTreeMap<K, V> { IntoIter { range: full_range, length: me.length } } else { - IntoIter { range: LeafRange::none(), length: 0 } + IntoIter { range: LazyLeafRange::none(), length: 0 } } } } -impl<K, V> Drop for Dropper<K, V> { +#[stable(feature = "btree_drop", since = "1.7.0")] +impl<K, V> Drop for IntoIter<K, V> { fn drop(&mut self) { - // Similar to advancing a non-fusing iterator. - fn next_or_end<K, V>( - this: &mut Dropper<K, V>, - ) -> Option<Handle<NodeRef<marker::Dying, K, V, marker::LeafOrInternal>, marker::KV>> - { - if this.remaining_length == 0 { - unsafe { ptr::read(&this.front).deallocating_end() } - None - } else { - this.remaining_length -= 1; - Some(unsafe { this.front.deallocating_next_unchecked() }) - } - } - - struct DropGuard<'a, K, V>(&'a mut Dropper<K, V>); + struct DropGuard<'a, K, V>(&'a mut IntoIter<K, V>); impl<'a, K, V> Drop for DropGuard<'a, K, V> { fn drop(&mut self) { // Continue the same loop we perform below. This only runs when unwinding, so we // don't have to care about panics this time (they'll abort). - while let Some(kv) = next_or_end(&mut self.0) { - kv.drop_key_val(); + while let Some(kv) = self.0.dying_next() { + // SAFETY: we consume the dying handle immediately. + unsafe { kv.drop_key_val() }; } } } - while let Some(kv) = next_or_end(self) { + while let Some(kv) = self.dying_next() { let guard = DropGuard(self); - kv.drop_key_val(); + // SAFETY: we don't touch the tree before consuming the dying handle. + unsafe { kv.drop_key_val() }; mem::forget(guard); } } } -#[stable(feature = "btree_drop", since = "1.7.0")] -impl<K, V> Drop for IntoIter<K, V> { - fn drop(&mut self) { - if let Some(front) = self.range.front.take() { - Dropper { front, remaining_length: self.length }; +impl<K, V> IntoIter<K, V> { + /// Core of a `next` method returning a dying KV handle, + /// invalidated by further calls to this function and some others. + fn dying_next( + &mut self, + ) -> Option<Handle<NodeRef<marker::Dying, K, V, marker::LeafOrInternal>, marker::KV>> { + if self.length == 0 { + self.range.deallocating_end(); + None + } else { + self.length -= 1; + Some(unsafe { self.range.deallocating_next_unchecked() }) + } + } + + /// Core of a `next_back` method returning a dying KV handle, + /// invalidated by further calls to this function and some others. + fn dying_next_back( + &mut self, + ) -> Option<Handle<NodeRef<marker::Dying, K, V, marker::LeafOrInternal>, marker::KV>> { + if self.length == 0 { + self.range.deallocating_end(); + None + } else { + self.length -= 1; + Some(unsafe { self.range.deallocating_next_back_unchecked() }) } } } @@ -1486,14 +1508,8 @@ impl<K, V> Iterator for IntoIter<K, V> { type Item = (K, V); fn next(&mut self) -> Option<(K, V)> { - if self.length == 0 { - None - } else { - self.length -= 1; - let front = self.range.front.as_mut().unwrap(); - let kv = unsafe { front.deallocating_next_unchecked() }; - Some(kv.into_key_val()) - } + // SAFETY: we consume the dying handle immediately. + self.dying_next().map(unsafe { |kv| kv.into_key_val() }) } fn size_hint(&self) -> (usize, Option<usize>) { @@ -1504,14 +1520,8 @@ impl<K, V> Iterator for IntoIter<K, V> { #[stable(feature = "rust1", since = "1.0.0")] impl<K, V> DoubleEndedIterator for IntoIter<K, V> { fn next_back(&mut self) -> Option<(K, V)> { - if self.length == 0 { - None - } else { - self.length -= 1; - let back = self.range.back.as_mut().unwrap(); - let kv = unsafe { back.deallocating_next_back_unchecked() }; - Some(kv.into_key_val()) - } + // SAFETY: we consume the dying handle immediately. + self.dying_next_back().map(unsafe { |kv| kv.into_key_val() }) } } @@ -1727,7 +1737,7 @@ impl<'a, K, V> Iterator for Range<'a, K, V> { type Item = (&'a K, &'a V); fn next(&mut self) -> Option<(&'a K, &'a V)> { - if self.inner.is_empty() { None } else { Some(unsafe { self.next_unchecked() }) } + self.inner.next_checked() } fn last(mut self) -> Option<(&'a K, &'a V)> { @@ -1777,12 +1787,6 @@ impl<K, V> ExactSizeIterator for ValuesMut<'_, K, V> { #[stable(feature = "fused", since = "1.26.0")] impl<K, V> FusedIterator for ValuesMut<'_, K, V> {} -impl<'a, K, V> Range<'a, K, V> { - unsafe fn next_unchecked(&mut self) -> (&'a K, &'a V) { - unsafe { self.inner.front.as_mut().unwrap_unchecked().next_unchecked() } - } -} - #[stable(feature = "map_into_keys_values", since = "1.54.0")] impl<K, V> Iterator for IntoKeys<K, V> { type Item = K; @@ -1862,13 +1866,7 @@ impl<K, V> FusedIterator for IntoValues<K, V> {} #[stable(feature = "btree_range", since = "1.17.0")] impl<'a, K, V> DoubleEndedIterator for Range<'a, K, V> { fn next_back(&mut self) -> Option<(&'a K, &'a V)> { - if self.inner.is_empty() { None } else { Some(unsafe { self.next_back_unchecked() }) } - } -} - -impl<'a, K, V> Range<'a, K, V> { - unsafe fn next_back_unchecked(&mut self) -> (&'a K, &'a V) { - unsafe { self.inner.back.as_mut().unwrap_unchecked().next_back_unchecked() } + self.inner.next_back_checked() } } @@ -1878,7 +1876,7 @@ impl<K, V> FusedIterator for Range<'_, K, V> {} #[stable(feature = "btree_range", since = "1.17.0")] impl<K, V> Clone for Range<'_, K, V> { fn clone(&self) -> Self { - Range { inner: LeafRange { front: self.inner.front, back: self.inner.back } } + Range { inner: self.inner.clone() } } } @@ -1887,7 +1885,7 @@ impl<'a, K, V> Iterator for RangeMut<'a, K, V> { type Item = (&'a K, &'a mut V); fn next(&mut self) -> Option<(&'a K, &'a mut V)> { - if self.inner.is_empty() { None } else { Some(unsafe { self.next_unchecked() }) } + self.inner.next_checked() } fn last(mut self) -> Option<(&'a K, &'a mut V)> { @@ -1903,34 +1901,16 @@ impl<'a, K, V> Iterator for RangeMut<'a, K, V> { } } -impl<'a, K, V> RangeMut<'a, K, V> { - unsafe fn next_unchecked(&mut self) -> (&'a K, &'a mut V) { - unsafe { self.inner.front.as_mut().unwrap_unchecked().next_unchecked() } - } - - /// Returns an iterator of references over the remaining items. - #[inline] - pub(super) fn iter(&self) -> Range<'_, K, V> { - Range { inner: self.inner.reborrow() } - } -} - #[stable(feature = "btree_range", since = "1.17.0")] impl<'a, K, V> DoubleEndedIterator for RangeMut<'a, K, V> { fn next_back(&mut self) -> Option<(&'a K, &'a mut V)> { - if self.inner.is_empty() { None } else { Some(unsafe { self.next_back_unchecked() }) } + self.inner.next_back_checked() } } #[stable(feature = "fused", since = "1.26.0")] impl<K, V> FusedIterator for RangeMut<'_, K, V> {} -impl<'a, K, V> RangeMut<'a, K, V> { - unsafe fn next_back_unchecked(&mut self) -> (&'a K, &'a mut V) { - unsafe { self.inner.back.as_mut().unwrap_unchecked().next_back_unchecked() } - } -} - #[stable(feature = "rust1", since = "1.0.0")] impl<K: Ord, V> FromIterator<(K, V)> for BTreeMap<K, V> { fn from_iter<T: IntoIterator<Item = (K, V)>>(iter: T) -> BTreeMap<K, V> { @@ -2036,6 +2016,20 @@ where } } +#[stable(feature = "std_collections_from_array", since = "1.56.0")] +impl<K: Ord, V, const N: usize> From<[(K, V); N]> for BTreeMap<K, V> { + /// ``` + /// use std::collections::BTreeMap; + /// + /// let map1 = BTreeMap::from([(1, 2), (3, 4)]); + /// let map2: BTreeMap<_, _> = [(1, 2), (3, 4)].into(); + /// assert_eq!(map1, map2); + /// ``` + fn from(arr: [(K, V); N]) -> Self { + core::array::IntoIter::new(arr).collect() + } +} + impl<K, V> BTreeMap<K, V> { /// Gets an iterator over the entries of the map, sorted by key. /// @@ -2063,9 +2057,9 @@ impl<K, V> BTreeMap<K, V> { if let Some(root) = &self.root { let full_range = root.reborrow().full_range(); - Iter { range: Range { inner: full_range }, length: self.length } + Iter { range: full_range, length: self.length } } else { - Iter { range: Range { inner: LeafRange::none() }, length: 0 } + Iter { range: LazyLeafRange::none(), length: 0 } } } @@ -2095,15 +2089,9 @@ impl<K, V> BTreeMap<K, V> { if let Some(root) = &mut self.root { let full_range = root.borrow_valmut().full_range(); - IterMut { - range: RangeMut { inner: full_range, _marker: PhantomData }, - length: self.length, - } + IterMut { range: full_range, length: self.length, _marker: PhantomData } } else { - IterMut { - range: RangeMut { inner: LeafRange::none(), _marker: PhantomData }, - length: 0, - } + IterMut { range: LazyLeafRange::none(), length: 0, _marker: PhantomData } } } @@ -2189,7 +2177,6 @@ impl<K, V> BTreeMap<K, V> { /// a.insert(1, "a"); /// assert_eq!(a.len(), 1); /// ``` - #[doc(alias = "length")] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_unstable(feature = "const_btree_new", issue = "71835")] pub const fn len(&self) -> usize { diff --git a/library/alloc/src/collections/btree/map/entry.rs b/library/alloc/src/collections/btree/map/entry.rs index 6b30d959773..5fec8dc2d13 100644 --- a/library/alloc/src/collections/btree/map/entry.rs +++ b/library/alloc/src/collections/btree/map/entry.rs @@ -14,6 +14,7 @@ use Entry::*; /// /// [`entry`]: BTreeMap::entry #[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr(not(test), rustc_diagnostic_item = "BTreeEntry")] pub enum Entry<'a, K: 'a, V: 'a> { /// A vacant entry. #[stable(feature = "rust1", since = "1.0.0")] diff --git a/library/alloc/src/collections/btree/map/tests.rs b/library/alloc/src/collections/btree/map/tests.rs index 3a74b6a6fa8..17e53848343 100644 --- a/library/alloc/src/collections/btree/map/tests.rs +++ b/library/alloc/src/collections/btree/map/tests.rs @@ -1786,13 +1786,6 @@ fn test_ord_absence() { } } -#[allow(dead_code)] -fn test_const() { - const MAP: &'static BTreeMap<(), ()> = &BTreeMap::new(); - const LEN: usize = MAP.len(); - const IS_EMPTY: bool = MAP.is_empty(); -} - #[test] fn test_occupied_entry_key() { let mut a = BTreeMap::new(); @@ -2173,3 +2166,10 @@ fn test_insert_remove_intertwined_ord_chaos() { } map.check_invariants(); } + +#[test] +fn from_array() { + let map = BTreeMap::from([(1, 2), (3, 4)]); + let unordered_duplicates = BTreeMap::from([(3, 4), (1, 2), (1, 2)]); + assert_eq!(map, unordered_duplicates); +} diff --git a/library/alloc/src/collections/btree/navigate.rs b/library/alloc/src/collections/btree/navigate.rs index 563c070dd0f..7b1d4d68c4f 100644 --- a/library/alloc/src/collections/btree/navigate.rs +++ b/library/alloc/src/collections/btree/navigate.rs @@ -1,12 +1,20 @@ use core::borrow::Borrow; +use core::hint; use core::ops::RangeBounds; use core::ptr; use super::node::{marker, ForceResult::*, Handle, NodeRef}; +// `front` and `back` are always both `None` or both `Some`. pub struct LeafRange<BorrowType, K, V> { - pub front: Option<Handle<NodeRef<BorrowType, K, V, marker::Leaf>, marker::Edge>>, - pub back: Option<Handle<NodeRef<BorrowType, K, V, marker::Leaf>, marker::Edge>>, + front: Option<Handle<NodeRef<BorrowType, K, V, marker::Leaf>, marker::Edge>>, + back: Option<Handle<NodeRef<BorrowType, K, V, marker::Leaf>, marker::Edge>>, +} + +impl<'a, K: 'a, V: 'a> Clone for LeafRange<marker::Immut<'a>, K, V> { + fn clone(&self) -> Self { + LeafRange { front: self.front.clone(), back: self.back.clone() } + } } impl<BorrowType, K, V> LeafRange<BorrowType, K, V> { @@ -14,7 +22,7 @@ impl<BorrowType, K, V> LeafRange<BorrowType, K, V> { LeafRange { front: None, back: None } } - pub fn is_empty(&self) -> bool { + fn is_empty(&self) -> bool { self.front == self.back } @@ -27,6 +35,203 @@ impl<BorrowType, K, V> LeafRange<BorrowType, K, V> { } } +impl<'a, K, V> LeafRange<marker::Immut<'a>, K, V> { + #[inline] + pub fn next_checked(&mut self) -> Option<(&'a K, &'a V)> { + self.perform_next_checked(|kv| kv.into_kv()) + } + + #[inline] + pub fn next_back_checked(&mut self) -> Option<(&'a K, &'a V)> { + self.perform_next_back_checked(|kv| kv.into_kv()) + } +} + +impl<'a, K, V> LeafRange<marker::ValMut<'a>, K, V> { + #[inline] + pub fn next_checked(&mut self) -> Option<(&'a K, &'a mut V)> { + self.perform_next_checked(|kv| unsafe { ptr::read(kv) }.into_kv_valmut()) + } + + #[inline] + pub fn next_back_checked(&mut self) -> Option<(&'a K, &'a mut V)> { + self.perform_next_back_checked(|kv| unsafe { ptr::read(kv) }.into_kv_valmut()) + } +} + +impl<BorrowType: marker::BorrowType, K, V> LeafRange<BorrowType, K, V> { + /// If possible, extract some result from the following KV and move to the edge beyond it. + fn perform_next_checked<F, R>(&mut self, f: F) -> Option<R> + where + F: Fn(&Handle<NodeRef<BorrowType, K, V, marker::LeafOrInternal>, marker::KV>) -> R, + { + if self.is_empty() { + None + } else { + super::mem::replace(self.front.as_mut().unwrap(), |front| { + let kv = front.next_kv().ok().unwrap(); + let result = f(&kv); + (kv.next_leaf_edge(), Some(result)) + }) + } + } + + /// If possible, extract some result from the preceding KV and move to the edge beyond it. + fn perform_next_back_checked<F, R>(&mut self, f: F) -> Option<R> + where + F: Fn(&Handle<NodeRef<BorrowType, K, V, marker::LeafOrInternal>, marker::KV>) -> R, + { + if self.is_empty() { + None + } else { + super::mem::replace(self.back.as_mut().unwrap(), |back| { + let kv = back.next_back_kv().ok().unwrap(); + let result = f(&kv); + (kv.next_back_leaf_edge(), Some(result)) + }) + } + } +} + +enum LazyLeafHandle<BorrowType, K, V> { + Root(NodeRef<BorrowType, K, V, marker::LeafOrInternal>), // not yet descended + Edge(Handle<NodeRef<BorrowType, K, V, marker::Leaf>, marker::Edge>), +} + +impl<'a, K: 'a, V: 'a> Clone for LazyLeafHandle<marker::Immut<'a>, K, V> { + fn clone(&self) -> Self { + match self { + LazyLeafHandle::Root(root) => LazyLeafHandle::Root(*root), + LazyLeafHandle::Edge(edge) => LazyLeafHandle::Edge(*edge), + } + } +} + +impl<BorrowType, K, V> LazyLeafHandle<BorrowType, K, V> { + fn reborrow(&self) -> LazyLeafHandle<marker::Immut<'_>, K, V> { + match self { + LazyLeafHandle::Root(root) => LazyLeafHandle::Root(root.reborrow()), + LazyLeafHandle::Edge(edge) => LazyLeafHandle::Edge(edge.reborrow()), + } + } +} + +// `front` and `back` are always both `None` or both `Some`. +pub struct LazyLeafRange<BorrowType, K, V> { + front: Option<LazyLeafHandle<BorrowType, K, V>>, + back: Option<LazyLeafHandle<BorrowType, K, V>>, +} + +impl<'a, K: 'a, V: 'a> Clone for LazyLeafRange<marker::Immut<'a>, K, V> { + fn clone(&self) -> Self { + LazyLeafRange { front: self.front.clone(), back: self.back.clone() } + } +} + +impl<BorrowType, K, V> LazyLeafRange<BorrowType, K, V> { + pub fn none() -> Self { + LazyLeafRange { front: None, back: None } + } + + /// Temporarily takes out another, immutable equivalent of the same range. + pub fn reborrow(&self) -> LazyLeafRange<marker::Immut<'_>, K, V> { + LazyLeafRange { + front: self.front.as_ref().map(|f| f.reborrow()), + back: self.back.as_ref().map(|b| b.reborrow()), + } + } +} + +impl<'a, K, V> LazyLeafRange<marker::Immut<'a>, K, V> { + #[inline] + pub unsafe fn next_unchecked(&mut self) -> (&'a K, &'a V) { + unsafe { self.init_front().unwrap().next_unchecked() } + } + + #[inline] + pub unsafe fn next_back_unchecked(&mut self) -> (&'a K, &'a V) { + unsafe { self.init_back().unwrap().next_back_unchecked() } + } +} + +impl<'a, K, V> LazyLeafRange<marker::ValMut<'a>, K, V> { + #[inline] + pub unsafe fn next_unchecked(&mut self) -> (&'a K, &'a mut V) { + unsafe { self.init_front().unwrap().next_unchecked() } + } + + #[inline] + pub unsafe fn next_back_unchecked(&mut self) -> (&'a K, &'a mut V) { + unsafe { self.init_back().unwrap().next_back_unchecked() } + } +} + +impl<K, V> LazyLeafRange<marker::Dying, K, V> { + fn take_front( + &mut self, + ) -> Option<Handle<NodeRef<marker::Dying, K, V, marker::Leaf>, marker::Edge>> { + match self.front.take()? { + LazyLeafHandle::Root(root) => Some(root.first_leaf_edge()), + LazyLeafHandle::Edge(edge) => Some(edge), + } + } + + #[inline] + pub unsafe fn deallocating_next_unchecked( + &mut self, + ) -> Handle<NodeRef<marker::Dying, K, V, marker::LeafOrInternal>, marker::KV> { + debug_assert!(self.front.is_some()); + let front = self.init_front().unwrap(); + unsafe { front.deallocating_next_unchecked() } + } + + #[inline] + pub unsafe fn deallocating_next_back_unchecked( + &mut self, + ) -> Handle<NodeRef<marker::Dying, K, V, marker::LeafOrInternal>, marker::KV> { + debug_assert!(self.back.is_some()); + let back = self.init_back().unwrap(); + unsafe { back.deallocating_next_back_unchecked() } + } + + #[inline] + pub fn deallocating_end(&mut self) { + if let Some(front) = self.take_front() { + front.deallocating_end() + } + } +} + +impl<BorrowType: marker::BorrowType, K, V> LazyLeafRange<BorrowType, K, V> { + fn init_front( + &mut self, + ) -> Option<&mut Handle<NodeRef<BorrowType, K, V, marker::Leaf>, marker::Edge>> { + if let Some(LazyLeafHandle::Root(root)) = &self.front { + self.front = Some(LazyLeafHandle::Edge(unsafe { ptr::read(root) }.first_leaf_edge())); + } + match &mut self.front { + None => None, + Some(LazyLeafHandle::Edge(edge)) => Some(edge), + // SAFETY: the code above would have replaced it. + Some(LazyLeafHandle::Root(_)) => unsafe { hint::unreachable_unchecked() }, + } + } + + fn init_back( + &mut self, + ) -> Option<&mut Handle<NodeRef<BorrowType, K, V, marker::Leaf>, marker::Edge>> { + if let Some(LazyLeafHandle::Root(root)) = &self.back { + self.back = Some(LazyLeafHandle::Edge(unsafe { ptr::read(root) }.last_leaf_edge())); + } + match &mut self.back { + None => None, + Some(LazyLeafHandle::Edge(edge)) => Some(edge), + // SAFETY: the code above would have replaced it. + Some(LazyLeafHandle::Root(_)) => unsafe { hint::unreachable_unchecked() }, + } + } +} + impl<BorrowType: marker::BorrowType, K, V> NodeRef<BorrowType, K, V, marker::LeafOrInternal> { /// Finds the distinct leaf edges delimiting a specified range in a tree. /// @@ -36,7 +241,7 @@ impl<BorrowType: marker::BorrowType, K, V> NodeRef<BorrowType, K, V, marker::Lea /// result will eventually reach the same edge. /// /// If there are no such edges, i.e., if the tree contains no key within - /// the range, returns a pair of empty options. + /// the range, returns an empty `front` and `back`. /// /// # Safety /// Unless `BorrowType` is `Immut`, do not use the handles to visit the same @@ -78,26 +283,13 @@ impl<BorrowType: marker::BorrowType, K, V> NodeRef<BorrowType, K, V, marker::Lea } } -/// Equivalent to `(root1.first_leaf_edge(), root2.last_leaf_edge())` but more efficient. fn full_range<BorrowType: marker::BorrowType, K, V>( root1: NodeRef<BorrowType, K, V, marker::LeafOrInternal>, root2: NodeRef<BorrowType, K, V, marker::LeafOrInternal>, -) -> LeafRange<BorrowType, K, V> { - let mut min_node = root1; - let mut max_node = root2; - loop { - let front = min_node.first_edge(); - let back = max_node.last_edge(); - match (front.force(), back.force()) { - (Leaf(f), Leaf(b)) => { - return LeafRange { front: Some(f), back: Some(b) }; - } - (Internal(min_int), Internal(max_int)) => { - min_node = min_int.descend(); - max_node = max_int.descend(); - } - _ => unreachable!("BTreeMap has different depths"), - }; +) -> LazyLeafRange<BorrowType, K, V> { + LazyLeafRange { + front: Some(LazyLeafHandle::Root(root1)), + back: Some(LazyLeafHandle::Root(root2)), } } @@ -117,7 +309,7 @@ impl<'a, K: 'a, V: 'a> NodeRef<marker::Immut<'a>, K, V, marker::LeafOrInternal> } /// Finds the pair of leaf edges delimiting an entire tree. - pub fn full_range(self) -> LeafRange<marker::Immut<'a>, K, V> { + pub fn full_range(self) -> LazyLeafRange<marker::Immut<'a>, K, V> { full_range(self, self) } } @@ -144,7 +336,7 @@ impl<'a, K: 'a, V: 'a> NodeRef<marker::ValMut<'a>, K, V, marker::LeafOrInternal> /// Splits a unique reference into a pair of leaf edges delimiting the full range of the tree. /// The results are non-unique references allowing mutation (of values only), so must be used /// with care. - pub fn full_range(self) -> LeafRange<marker::ValMut<'a>, K, V> { + pub fn full_range(self) -> LazyLeafRange<marker::ValMut<'a>, K, V> { // We duplicate the root NodeRef here -- we will never visit the same KV // twice, and never end up with overlapping value references. let self2 = unsafe { ptr::read(&self) }; @@ -156,7 +348,7 @@ impl<K, V> NodeRef<marker::Dying, K, V, marker::LeafOrInternal> { /// Splits a unique reference into a pair of leaf edges delimiting the full range of the tree. /// The results are non-unique references allowing massively destructive mutation, so must be /// used with the utmost care. - pub fn full_range(self) -> LeafRange<marker::Dying, K, V> { + pub fn full_range(self) -> LazyLeafRange<marker::Dying, K, V> { // We duplicate the root NodeRef here -- we will never access it in a way // that overlaps references obtained from the root. let self2 = unsafe { ptr::read(&self) }; @@ -191,7 +383,7 @@ impl<BorrowType: marker::BorrowType, K, V> /// Given a leaf edge handle, returns [`Result::Ok`] with a handle to the neighboring KV /// on the left side, which is either in the same leaf node or in an ancestor node. /// If the leaf edge is the first one in the tree, returns [`Result::Err`] with the root node. - pub fn next_back_kv( + fn next_back_kv( self, ) -> Result< Handle<NodeRef<BorrowType, K, V, marker::LeafOrInternal>, marker::KV>, @@ -216,7 +408,7 @@ impl<BorrowType: marker::BorrowType, K, V> /// Given an internal edge handle, returns [`Result::Ok`] with a handle to the neighboring KV /// on the right side, which is either in the same internal node or in an ancestor node. /// If the internal edge is the last one in the tree, returns [`Result::Err`] with the root node. - pub fn next_kv( + fn next_kv( self, ) -> Result< Handle<NodeRef<BorrowType, K, V, marker::Internal>, marker::KV>, @@ -250,7 +442,7 @@ impl<K, V> Handle<NodeRef<marker::Dying, K, V, marker::Leaf>, marker::Edge> { /// - The returned KV handle is only valid to access the key and value, /// and only valid until the next call to this method or counterpart /// `deallocating_next_back`. - pub unsafe fn deallocating_next( + unsafe fn deallocating_next( self, ) -> Option<(Self, Handle<NodeRef<marker::Dying, K, V, marker::LeafOrInternal>, marker::KV>)> { @@ -302,7 +494,7 @@ impl<K, V> Handle<NodeRef<marker::Dying, K, V, marker::Leaf>, marker::Edge> { /// both sides of the tree, and have hit the same edge. As it is intended /// only to be called when all keys and values have been returned, /// no cleanup is done on any of the keys or values. - pub fn deallocating_end(self) { + fn deallocating_end(self) { let mut edge = self.forget_node_type(); while let Some(parent_edge) = unsafe { edge.into_node().deallocate_and_ascend() } { edge = parent_edge.forget_node_type(); @@ -316,10 +508,9 @@ impl<'a, K, V> Handle<NodeRef<marker::Immut<'a>, K, V, marker::Leaf>, marker::Ed /// /// # Safety /// There must be another KV in the direction travelled. - pub unsafe fn next_unchecked(&mut self) -> (&'a K, &'a V) { + unsafe fn next_unchecked(&mut self) -> (&'a K, &'a V) { super::mem::replace(self, |leaf_edge| { - let kv = leaf_edge.next_kv(); - let kv = unsafe { kv.ok().unwrap_unchecked() }; + let kv = leaf_edge.next_kv().ok().unwrap(); (kv.next_leaf_edge(), kv.into_kv()) }) } @@ -329,10 +520,9 @@ impl<'a, K, V> Handle<NodeRef<marker::Immut<'a>, K, V, marker::Leaf>, marker::Ed /// /// # Safety /// There must be another KV in the direction travelled. - pub unsafe fn next_back_unchecked(&mut self) -> (&'a K, &'a V) { + unsafe fn next_back_unchecked(&mut self) -> (&'a K, &'a V) { super::mem::replace(self, |leaf_edge| { - let kv = leaf_edge.next_back_kv(); - let kv = unsafe { kv.ok().unwrap_unchecked() }; + let kv = leaf_edge.next_back_kv().ok().unwrap(); (kv.next_back_leaf_edge(), kv.into_kv()) }) } @@ -344,10 +534,9 @@ impl<'a, K, V> Handle<NodeRef<marker::ValMut<'a>, K, V, marker::Leaf>, marker::E /// /// # Safety /// There must be another KV in the direction travelled. - pub unsafe fn next_unchecked(&mut self) -> (&'a K, &'a mut V) { + unsafe fn next_unchecked(&mut self) -> (&'a K, &'a mut V) { let kv = super::mem::replace(self, |leaf_edge| { - let kv = leaf_edge.next_kv(); - let kv = unsafe { kv.ok().unwrap_unchecked() }; + let kv = leaf_edge.next_kv().ok().unwrap(); (unsafe { ptr::read(&kv) }.next_leaf_edge(), kv) }); // Doing this last is faster, according to benchmarks. @@ -359,10 +548,9 @@ impl<'a, K, V> Handle<NodeRef<marker::ValMut<'a>, K, V, marker::Leaf>, marker::E /// /// # Safety /// There must be another KV in the direction travelled. - pub unsafe fn next_back_unchecked(&mut self) -> (&'a K, &'a mut V) { + unsafe fn next_back_unchecked(&mut self) -> (&'a K, &'a mut V) { let kv = super::mem::replace(self, |leaf_edge| { - let kv = leaf_edge.next_back_kv(); - let kv = unsafe { kv.ok().unwrap_unchecked() }; + let kv = leaf_edge.next_back_kv().ok().unwrap(); (unsafe { ptr::read(&kv) }.next_back_leaf_edge(), kv) }); // Doing this last is faster, according to benchmarks. @@ -383,12 +571,10 @@ impl<K, V> Handle<NodeRef<marker::Dying, K, V, marker::Leaf>, marker::Edge> { /// /// The only safe way to proceed with the updated handle is to compare it, drop it, /// or call this method or counterpart `deallocating_next_back_unchecked` again. - pub unsafe fn deallocating_next_unchecked( + unsafe fn deallocating_next_unchecked( &mut self, ) -> Handle<NodeRef<marker::Dying, K, V, marker::LeafOrInternal>, marker::KV> { - super::mem::replace(self, |leaf_edge| unsafe { - leaf_edge.deallocating_next().unwrap_unchecked() - }) + super::mem::replace(self, |leaf_edge| unsafe { leaf_edge.deallocating_next().unwrap() }) } /// Moves the leaf edge handle to the previous leaf edge and returns the key and value @@ -403,11 +589,11 @@ impl<K, V> Handle<NodeRef<marker::Dying, K, V, marker::Leaf>, marker::Edge> { /// /// The only safe way to proceed with the updated handle is to compare it, drop it, /// or call this method or counterpart `deallocating_next_unchecked` again. - pub unsafe fn deallocating_next_back_unchecked( + unsafe fn deallocating_next_back_unchecked( &mut self, ) -> Handle<NodeRef<marker::Dying, K, V, marker::LeafOrInternal>, marker::KV> { super::mem::replace(self, |leaf_edge| unsafe { - leaf_edge.deallocating_next_back().unwrap_unchecked() + leaf_edge.deallocating_next_back().unwrap() }) } } @@ -508,9 +694,7 @@ impl<BorrowType: marker::BorrowType, K, V> } /// Returns the leaf edge closest to a KV for backward navigation. - pub fn next_back_leaf_edge( - self, - ) -> Handle<NodeRef<BorrowType, K, V, marker::Leaf>, marker::Edge> { + fn next_back_leaf_edge(self) -> Handle<NodeRef<BorrowType, K, V, marker::Leaf>, marker::Edge> { match self.force() { Leaf(leaf_kv) => leaf_kv.left_edge(), Internal(internal_kv) => { diff --git a/library/alloc/src/collections/btree/node.rs b/library/alloc/src/collections/btree/node.rs index 3c453529ba8..8f6a2ec9ebd 100644 --- a/library/alloc/src/collections/btree/node.rs +++ b/library/alloc/src/collections/btree/node.rs @@ -167,7 +167,7 @@ type BoxedNode<K, V> = NonNull<LeafNode<K, V>>; /// carry a lifetime, because we want it to return `&'a` references. /// Therefore, we define it only for the least powerful type `Immut<'a>`. /// - We cannot get implicit coercion from say `Mut<'a>` to `Immut<'a>`. -/// Therefore, we have to explicitly call `reborrow` on a more powerfull +/// Therefore, we have to explicitly call `reborrow` on a more powerful /// `NodeRef` in order to reach a method like `into_kv`. /// /// All methods on `NodeRef` that return some kind of reference, either: @@ -409,7 +409,7 @@ impl<K, V> NodeRef<marker::Dying, K, V, marker::LeafOrInternal> { impl<'a, K, V, Type> NodeRef<marker::Mut<'a>, K, V, Type> { /// Temporarily takes out another mutable reference to the same node. Beware, as - /// this method is very dangerous, doubly so since it may not immediately appear + /// this method is very dangerous, doubly so since it might not immediately appear /// dangerous. /// /// Because mutable pointers can roam anywhere around the tree, the returned @@ -777,7 +777,7 @@ impl<BorrowType, K, V, NodeType, HandleType> impl<'a, K, V, NodeType, HandleType> Handle<NodeRef<marker::Mut<'a>, K, V, NodeType>, HandleType> { /// Temporarily takes out another mutable handle on the same location. Beware, as - /// this method is very dangerous, doubly so since it may not immediately appear + /// this method is very dangerous, doubly so since it might not immediately appear /// dangerous. /// /// For details, see `NodeRef::reborrow_mut`. @@ -1058,7 +1058,9 @@ impl<'a, K: 'a, V: 'a, NodeType> Handle<NodeRef<marker::Mut<'a>, K, V, NodeType> impl<K, V, NodeType> Handle<NodeRef<marker::Dying, K, V, NodeType>, marker::KV> { /// Extracts the key and value that the KV handle refers to. - pub fn into_key_val(mut self) -> (K, V) { + /// # Safety + /// The node that the handle refers to must not yet have been deallocated. + pub unsafe fn into_key_val(mut self) -> (K, V) { debug_assert!(self.idx < self.node.len()); let leaf = self.node.as_leaf_dying(); unsafe { @@ -1069,8 +1071,10 @@ impl<K, V, NodeType> Handle<NodeRef<marker::Dying, K, V, NodeType>, marker::KV> } /// Drops the key and value that the KV handle refers to. + /// # Safety + /// The node that the handle refers to must not yet have been deallocated. #[inline] - pub fn drop_key_val(mut self) { + pub unsafe fn drop_key_val(mut self) { debug_assert!(self.idx < self.node.len()); let leaf = self.node.as_leaf_dying(); unsafe { diff --git a/library/alloc/src/collections/btree/set.rs b/library/alloc/src/collections/btree/set.rs index 737932d931c..0c268ad32b2 100644 --- a/library/alloc/src/collections/btree/set.rs +++ b/library/alloc/src/collections/btree/set.rs @@ -59,6 +59,14 @@ use super::Recover; /// println!("{}", book); /// } /// ``` +/// +/// A `BTreeSet` with a known list of items can be initialized from an array: +/// +/// ``` +/// use std::collections::BTreeSet; +/// +/// let set = BTreeSet::from([1, 2, 3]); +/// ``` #[derive(Hash, PartialEq, Eq, Ord, PartialOrd)] #[stable(feature = "rust1", since = "1.0.0")] #[cfg_attr(not(test), rustc_diagnostic_item = "BTreeSet")] @@ -810,7 +818,6 @@ impl<T> BTreeSet<T> { /// assert_eq!(set.remove(&2), true); /// assert_eq!(set.remove(&2), false); /// ``` - #[doc(alias = "delete")] #[stable(feature = "rust1", since = "1.0.0")] pub fn remove<Q: ?Sized>(&mut self, value: &Q) -> bool where @@ -847,6 +854,7 @@ impl<T> BTreeSet<T> { /// Retains only the elements specified by the predicate. /// /// In other words, remove all elements `e` such that `f(&e)` returns `false`. + /// The elements are visited in ascending order. /// /// # Examples /// @@ -904,8 +912,8 @@ impl<T> BTreeSet<T> { self.map.append(&mut other.map); } - /// Splits the collection into two at the given key. Returns everything after the given key, - /// including the key. + /// Splits the collection into two at the given value. Returns everything after the given value, + /// including the value. /// /// # Examples /// @@ -934,25 +942,27 @@ impl<T> BTreeSet<T> { /// assert!(b.contains(&41)); /// ``` #[stable(feature = "btree_split_off", since = "1.11.0")] - pub fn split_off<Q: ?Sized + Ord>(&mut self, key: &Q) -> Self + pub fn split_off<Q: ?Sized + Ord>(&mut self, value: &Q) -> Self where T: Borrow<Q> + Ord, { - BTreeSet { map: self.map.split_off(key) } + BTreeSet { map: self.map.split_off(value) } } - /// Creates an iterator which uses a closure to determine if a value should be removed. + /// Creates an iterator that visits all values in ascending order and uses a closure + /// to determine if a value should be removed. /// - /// If the closure returns true, then the value is removed and yielded. - /// If the closure returns false, the value will remain in the list and will not be yielded - /// by the iterator. + /// If the closure returns `true`, the value is removed from the set and yielded. If + /// the closure returns `false`, or panics, the value remains in the set and will + /// not be yielded. /// - /// If the iterator is only partially consumed or not consumed at all, each of the remaining - /// values will still be subjected to the closure and removed and dropped if it returns true. + /// If the iterator is only partially consumed or not consumed at all, each of the + /// remaining values is still subjected to the closure and removed and dropped if it + /// returns `true`. /// - /// It is unspecified how many more values will be subjected to the closure - /// if a panic occurs in the closure, or if a panic occurs while dropping a value, or if the - /// `DrainFilter` itself is leaked. + /// It is unspecified how many more values will be subjected to the closure if a + /// panic occurs in the closure, or if a panic occurs while dropping a value, or if + /// the `DrainFilter` itself is leaked. /// /// # Examples /// @@ -1021,7 +1031,6 @@ impl<T> BTreeSet<T> { /// v.insert(1); /// assert_eq!(v.len(), 1); /// ``` - #[doc(alias = "length")] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_unstable(feature = "const_btree_new", issue = "71835")] pub const fn len(&self) -> usize { @@ -1056,6 +1065,20 @@ impl<T: Ord> FromIterator<T> for BTreeSet<T> { } } +#[stable(feature = "std_collections_from_array", since = "1.56.0")] +impl<T: Ord, const N: usize> From<[T; N]> for BTreeSet<T> { + /// ``` + /// use std::collections::BTreeSet; + /// + /// let set1 = BTreeSet::from([1, 2, 3, 4]); + /// let set2: BTreeSet<_> = [1, 2, 3, 4].into(); + /// assert_eq!(set1, set2); + /// ``` + fn from(arr: [T; N]) -> Self { + core::array::IntoIter::new(arr).collect() + } +} + #[stable(feature = "rust1", since = "1.0.0")] impl<T> IntoIterator for BTreeSet<T> { type Item = T; diff --git a/library/alloc/src/collections/btree/set/tests.rs b/library/alloc/src/collections/btree/set/tests.rs index 4cb6e3d6619..5d590a26281 100644 --- a/library/alloc/src/collections/btree/set/tests.rs +++ b/library/alloc/src/collections/btree/set/tests.rs @@ -16,13 +16,6 @@ fn test_clone_eq() { assert_eq!(m.clone(), m); } -#[allow(dead_code)] -fn test_const() { - const SET: &'static BTreeSet<()> = &BTreeSet::new(); - const LEN: usize = SET.len(); - const IS_EMPTY: bool = SET.is_empty(); -} - #[test] fn test_iter_min_max() { let mut a = BTreeSet::new(); @@ -738,3 +731,10 @@ fn test_split_off_large_random_sorted() { assert!(set.into_iter().eq(data.clone().into_iter().filter(|x| *x < key))); assert!(right.into_iter().eq(data.into_iter().filter(|x| *x >= key))); } + +#[test] +fn from_array() { + let set = BTreeSet::from([1, 2, 3, 4]); + let unordered_duplicates = BTreeSet::from([4, 1, 4, 3, 2]); + assert_eq!(set, unordered_duplicates); +} diff --git a/library/alloc/src/collections/linked_list.rs b/library/alloc/src/collections/linked_list.rs index 1a58ad51f78..7aa24ff4afa 100644 --- a/library/alloc/src/collections/linked_list.rs +++ b/library/alloc/src/collections/linked_list.rs @@ -31,6 +31,13 @@ mod tests; /// The `LinkedList` allows pushing and popping elements at either end /// in constant time. /// +/// A `LinkedList` with a known list of items can be initialized from an array: +/// ``` +/// use std::collections::LinkedList; +/// +/// let list = LinkedList::from([1, 2, 3]); +/// ``` +/// /// NOTE: It is almost always better to use `Vec` or `VecDeque` because /// array-based containers are generally faster, /// more memory efficient, and make better use of CPU cache. @@ -586,7 +593,6 @@ impl<T> LinkedList<T> { /// dl.push_back(3); /// assert_eq!(dl.len(), 3); /// ``` - #[doc(alias = "length")] #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn len(&self) -> usize { @@ -1243,6 +1249,20 @@ impl<'a, T> Cursor<'a, T> { prev.map(|prev| &(*prev.as_ptr()).element) } } + + /// Provides a reference to the front element of the cursor's parent list, + /// or None if the list is empty. + #[unstable(feature = "linked_list_cursors", issue = "58533")] + pub fn front(&self) -> Option<&'a T> { + self.list.front() + } + + /// Provides a reference to the back element of the cursor's parent list, + /// or None if the list is empty. + #[unstable(feature = "linked_list_cursors", issue = "58533")] + pub fn back(&self) -> Option<&'a T> { + self.list.back() + } } impl<'a, T> CursorMut<'a, T> { @@ -1506,6 +1526,135 @@ impl<'a, T> CursorMut<'a, T> { self.index = 0; unsafe { self.list.split_off_before_node(self.current, split_off_idx) } } + + /// Appends an element to the front of the cursor's parent list. The node + /// that the cursor points to is unchanged, even if it is the "ghost" node. + /// + /// This operation should compute in O(1) time. + // `push_front` continues to point to "ghost" when it addes a node to mimic + // the behavior of `insert_before` on an empty list. + #[unstable(feature = "linked_list_cursors", issue = "58533")] + pub fn push_front(&mut self, elt: T) { + // Safety: We know that `push_front` does not change the position in + // memory of other nodes. This ensures that `self.current` remains + // valid. + self.list.push_front(elt); + self.index += 1; + } + + /// Appends an element to the back of the cursor's parent list. The node + /// that the cursor points to is unchanged, even if it is the "ghost" node. + /// + /// This operation should compute in O(1) time. + #[unstable(feature = "linked_list_cursors", issue = "58533")] + pub fn push_back(&mut self, elt: T) { + // Safety: We know that `push_back` does not change the position in + // memory of other nodes. This ensures that `self.current` remains + // valid. + self.list.push_back(elt); + if self.current().is_none() { + // The index of "ghost" is the length of the list, so we just need + // to increment self.index to reflect the new length of the list. + self.index += 1; + } + } + + /// Removes the first element from the cursor's parent list and returns it, + /// or None if the list is empty. The element the cursor points to remains + /// unchanged, unless it was pointing to the front element. In that case, it + /// points to the new front element. + /// + /// This operation should compute in O(1) time. + #[unstable(feature = "linked_list_cursors", issue = "58533")] + pub fn pop_front(&mut self) -> Option<T> { + // We can't check if current is empty, we must check the list directly. + // It is possible for `self.current == None` and the list to be + // non-empty. + if self.list.is_empty() { + None + } else { + // We can't point to the node that we pop. Copying the behavior of + // `remove_current`, we move on the the next node in the sequence. + // If the list is of length 1 then we end pointing to the "ghost" + // node at index 0, which is expected. + if self.list.head == self.current { + self.move_next(); + } else { + self.index -= 1; + } + self.list.pop_front() + } + } + + /// Removes the last element from the cursor's parent list and returns it, + /// or None if the list is empty. The element the cursor points to remains + /// unchanged, unless it was pointing to the back element. In that case, it + /// points to the "ghost" element. + /// + /// This operation should compute in O(1) time. + #[unstable(feature = "linked_list_cursors", issue = "58533")] + pub fn pop_back(&mut self) -> Option<T> { + if self.list.is_empty() { + None + } else { + if self.list.tail == self.current { + // The index now reflects the length of the list. It was the + // length of the list minus 1, but now the list is 1 smaller. No + // change is needed for `index`. + self.current = None; + } else if self.current.is_none() { + self.index = self.list.len - 1; + } + self.list.pop_back() + } + } + + /// Provides a reference to the front element of the cursor's parent list, + /// or None if the list is empty. + #[unstable(feature = "linked_list_cursors", issue = "58533")] + pub fn front(&self) -> Option<&T> { + self.list.front() + } + + /// Provides a mutable reference to the front element of the cursor's + /// parent list, or None if the list is empty. + #[unstable(feature = "linked_list_cursors", issue = "58533")] + pub fn front_mut(&mut self) -> Option<&mut T> { + self.list.front_mut() + } + + /// Provides a reference to the back element of the cursor's parent list, + /// or None if the list is empty. + #[unstable(feature = "linked_list_cursors", issue = "58533")] + pub fn back(&self) -> Option<&T> { + self.list.back() + } + + /// Provides a mutable reference to back element of the cursor's parent + /// list, or `None` if the list is empty. + /// + /// # Examples + /// Building and mutating a list with a cursor, then getting the back element: + /// ``` + /// #![feature(linked_list_cursors)] + /// use std::collections::LinkedList; + /// let mut dl = LinkedList::new(); + /// dl.push_front(3); + /// dl.push_front(2); + /// dl.push_front(1); + /// let mut cursor = dl.cursor_front_mut(); + /// *cursor.current().unwrap() = 99; + /// *cursor.back_mut().unwrap() = 0; + /// let mut contents = dl.into_iter(); + /// assert_eq!(contents.next(), Some(99)); + /// assert_eq!(contents.next(), Some(2)); + /// assert_eq!(contents.next(), Some(0)); + /// assert_eq!(contents.next(), None); + /// ``` + #[unstable(feature = "linked_list_cursors", issue = "58533")] + pub fn back_mut(&mut self) -> Option<&mut T> { + self.list.back_mut() + } } /// An iterator produced by calling `drain_filter` on LinkedList. @@ -1759,6 +1908,20 @@ impl<T: Hash> Hash for LinkedList<T> { } } +#[stable(feature = "std_collections_from_array", since = "1.56.0")] +impl<T, const N: usize> From<[T; N]> for LinkedList<T> { + /// ``` + /// use std::collections::LinkedList; + /// + /// let list1 = LinkedList::from([1, 2, 3, 4]); + /// let list2: LinkedList<_> = [1, 2, 3, 4].into(); + /// assert_eq!(list1, list2); + /// ``` + fn from(arr: [T; N]) -> Self { + core::array::IntoIter::new(arr).collect() + } +} + // Ensure that `LinkedList` and its read-only iterators are covariant in their type parameters. #[allow(dead_code)] fn assert_covariance() { diff --git a/library/alloc/src/collections/linked_list/tests.rs b/library/alloc/src/collections/linked_list/tests.rs index ad643a7bdf1..5a65ed7a962 100644 --- a/library/alloc/src/collections/linked_list/tests.rs +++ b/library/alloc/src/collections/linked_list/tests.rs @@ -428,3 +428,50 @@ fn test_cursor_mut_insert() { check_links(&m); assert_eq!(m.iter().cloned().collect::<Vec<_>>(), &[200, 201, 202, 203, 1, 100, 101]); } + +#[test] +fn test_cursor_push_front_back() { + let mut ll: LinkedList<u32> = LinkedList::new(); + ll.extend(&[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]); + let mut c = ll.cursor_front_mut(); + assert_eq!(c.current(), Some(&mut 1)); + assert_eq!(c.index(), Some(0)); + c.push_front(0); + assert_eq!(c.current(), Some(&mut 1)); + assert_eq!(c.peek_prev(), Some(&mut 0)); + assert_eq!(c.index(), Some(1)); + c.push_back(11); + drop(c); + let p = ll.cursor_back().front().unwrap(); + assert_eq!(p, &0); + assert_eq!(ll, (0..12).collect()); + check_links(&ll); +} + +#[test] +fn test_cursor_pop_front_back() { + let mut ll: LinkedList<u32> = LinkedList::new(); + ll.extend(&[1, 2, 3, 4, 5, 6]); + let mut c = ll.cursor_back_mut(); + assert_eq!(c.pop_front(), Some(1)); + c.move_prev(); + c.move_prev(); + c.move_prev(); + assert_eq!(c.pop_back(), Some(6)); + let c = c.as_cursor(); + assert_eq!(c.front(), Some(&2)); + assert_eq!(c.back(), Some(&5)); + assert_eq!(c.index(), Some(1)); + drop(c); + assert_eq!(ll, (2..6).collect()); + check_links(&ll); + let mut c = ll.cursor_back_mut(); + assert_eq!(c.current(), Some(&mut 5)); + assert_eq!(c.index, 3); + assert_eq!(c.pop_back(), Some(5)); + assert_eq!(c.current(), None); + assert_eq!(c.index, 3); + assert_eq!(c.pop_back(), Some(4)); + assert_eq!(c.current(), None); + assert_eq!(c.index, 2); +} diff --git a/library/alloc/src/collections/mod.rs b/library/alloc/src/collections/mod.rs index b9b3d650ea2..0d442011921 100644 --- a/library/alloc/src/collections/mod.rs +++ b/library/alloc/src/collections/mod.rs @@ -58,7 +58,31 @@ use core::fmt::Display; /// The error type for `try_reserve` methods. #[derive(Clone, PartialEq, Eq, Debug)] #[unstable(feature = "try_reserve", reason = "new API", issue = "48043")] -pub enum TryReserveError { +pub struct TryReserveError { + kind: TryReserveErrorKind, +} + +impl TryReserveError { + /// Details about the allocation that caused the error + #[inline] + #[unstable( + feature = "try_reserve_kind", + reason = "Uncertain how much info should be exposed", + issue = "48043" + )] + pub fn kind(&self) -> TryReserveErrorKind { + self.kind.clone() + } +} + +/// Details of the allocation that caused a `TryReserveError` +#[derive(Clone, PartialEq, Eq, Debug)] +#[unstable( + feature = "try_reserve_kind", + reason = "Uncertain how much info should be exposed", + issue = "48043" +)] +pub enum TryReserveErrorKind { /// Error due to the computed capacity exceeding the collection's maximum /// (usually `isize::MAX` bytes). CapacityOverflow, @@ -81,11 +105,24 @@ pub enum TryReserveError { }, } +#[unstable( + feature = "try_reserve_kind", + reason = "Uncertain how much info should be exposed", + issue = "48043" +)] +impl From<TryReserveErrorKind> for TryReserveError { + #[inline] + fn from(kind: TryReserveErrorKind) -> Self { + Self { kind } + } +} + #[unstable(feature = "try_reserve", reason = "new API", issue = "48043")] impl From<LayoutError> for TryReserveError { + /// Always evaluates to [`TryReserveErrorKind::CapacityOverflow`]. #[inline] fn from(_: LayoutError) -> Self { - TryReserveError::CapacityOverflow + TryReserveErrorKind::CapacityOverflow.into() } } @@ -96,11 +133,13 @@ impl Display for TryReserveError { fmt: &mut core::fmt::Formatter<'_>, ) -> core::result::Result<(), core::fmt::Error> { fmt.write_str("memory allocation failed")?; - let reason = match &self { - TryReserveError::CapacityOverflow => { + let reason = match self.kind { + TryReserveErrorKind::CapacityOverflow => { " because the computed capacity exceeded the collection's maximum" } - TryReserveError::AllocError { .. } => " because the memory allocator returned a error", + TryReserveErrorKind::AllocError { .. } => { + " because the memory allocator returned a error" + } }; fmt.write_str(reason) } diff --git a/library/alloc/src/collections/vec_deque/drain.rs b/library/alloc/src/collections/vec_deque/drain.rs index 4ffb435d1e3..dfa0227dea3 100644 --- a/library/alloc/src/collections/vec_deque/drain.rs +++ b/library/alloc/src/collections/vec_deque/drain.rs @@ -2,6 +2,8 @@ use core::iter::FusedIterator; use core::ptr::{self, NonNull}; use core::{fmt, mem}; +use crate::alloc::{Allocator, Global}; + use super::{count, Iter, VecDeque}; /// A draining iterator over the elements of a `VecDeque`. @@ -11,15 +13,19 @@ use super::{count, Iter, VecDeque}; /// /// [`drain`]: VecDeque::drain #[stable(feature = "drain", since = "1.6.0")] -pub struct Drain<'a, T: 'a> { +pub struct Drain< + 'a, + T: 'a, + #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, +> { pub(crate) after_tail: usize, pub(crate) after_head: usize, pub(crate) iter: Iter<'a, T>, - pub(crate) deque: NonNull<VecDeque<T>>, + pub(crate) deque: NonNull<VecDeque<T, A>>, } #[stable(feature = "collection_debug", since = "1.17.0")] -impl<T: fmt::Debug> fmt::Debug for Drain<'_, T> { +impl<T: fmt::Debug, A: Allocator> fmt::Debug for Drain<'_, T, A> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_tuple("Drain") .field(&self.after_tail) @@ -30,16 +36,16 @@ impl<T: fmt::Debug> fmt::Debug for Drain<'_, T> { } #[stable(feature = "drain", since = "1.6.0")] -unsafe impl<T: Sync> Sync for Drain<'_, T> {} +unsafe impl<T: Sync, A: Allocator + Sync> Sync for Drain<'_, T, A> {} #[stable(feature = "drain", since = "1.6.0")] -unsafe impl<T: Send> Send for Drain<'_, T> {} +unsafe impl<T: Send, A: Allocator + Send> Send for Drain<'_, T, A> {} #[stable(feature = "drain", since = "1.6.0")] -impl<T> Drop for Drain<'_, T> { +impl<T, A: Allocator> Drop for Drain<'_, T, A> { fn drop(&mut self) { - struct DropGuard<'r, 'a, T>(&'r mut Drain<'a, T>); + struct DropGuard<'r, 'a, T, A: Allocator>(&'r mut Drain<'a, T, A>); - impl<'r, 'a, T> Drop for DropGuard<'r, 'a, T> { + impl<'r, 'a, T, A: Allocator> Drop for DropGuard<'r, 'a, T, A> { fn drop(&mut self) { self.0.for_each(drop); @@ -96,7 +102,7 @@ impl<T> Drop for Drain<'_, T> { } #[stable(feature = "drain", since = "1.6.0")] -impl<T> Iterator for Drain<'_, T> { +impl<T, A: Allocator> Iterator for Drain<'_, T, A> { type Item = T; #[inline] @@ -111,7 +117,7 @@ impl<T> Iterator for Drain<'_, T> { } #[stable(feature = "drain", since = "1.6.0")] -impl<T> DoubleEndedIterator for Drain<'_, T> { +impl<T, A: Allocator> DoubleEndedIterator for Drain<'_, T, A> { #[inline] fn next_back(&mut self) -> Option<T> { self.iter.next_back().map(|elt| unsafe { ptr::read(elt) }) @@ -119,7 +125,7 @@ impl<T> DoubleEndedIterator for Drain<'_, T> { } #[stable(feature = "drain", since = "1.6.0")] -impl<T> ExactSizeIterator for Drain<'_, T> {} +impl<T, A: Allocator> ExactSizeIterator for Drain<'_, T, A> {} #[stable(feature = "fused", since = "1.26.0")] -impl<T> FusedIterator for Drain<'_, T> {} +impl<T, A: Allocator> FusedIterator for Drain<'_, T, A> {} diff --git a/library/alloc/src/collections/vec_deque/into_iter.rs b/library/alloc/src/collections/vec_deque/into_iter.rs index 1c635dd4f27..5f13c3bf303 100644 --- a/library/alloc/src/collections/vec_deque/into_iter.rs +++ b/library/alloc/src/collections/vec_deque/into_iter.rs @@ -1,5 +1,7 @@ use core::fmt; -use core::iter::{FusedIterator, TrustedLen, TrustedRandomAccess}; +use core::iter::{FusedIterator, TrustedLen}; + +use crate::alloc::{Allocator, Global}; use super::VecDeque; @@ -11,19 +13,22 @@ use super::VecDeque; /// [`into_iter`]: VecDeque::into_iter #[derive(Clone)] #[stable(feature = "rust1", since = "1.0.0")] -pub struct IntoIter<T> { - pub(crate) inner: VecDeque<T>, +pub struct IntoIter< + T, + #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, +> { + pub(crate) inner: VecDeque<T, A>, } #[stable(feature = "collection_debug", since = "1.17.0")] -impl<T: fmt::Debug> fmt::Debug for IntoIter<T> { +impl<T: fmt::Debug, A: Allocator> fmt::Debug for IntoIter<T, A> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_tuple("IntoIter").field(&self.inner).finish() } } #[stable(feature = "rust1", since = "1.0.0")] -impl<T> Iterator for IntoIter<T> { +impl<T, A: Allocator> Iterator for IntoIter<T, A> { type Item = T; #[inline] @@ -36,26 +41,10 @@ impl<T> Iterator for IntoIter<T> { let len = self.inner.len(); (len, Some(len)) } - - #[inline] - unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item - where - Self: TrustedRandomAccess, - { - // Safety: The TrustedRandomAccess contract requires that callers only pass an index - // that is in bounds. - // Additionally Self: TrustedRandomAccess is only implemented for T: Copy which means even - // multiple repeated reads of the same index would be safe and the - // values are !Drop, thus won't suffer from double drops. - unsafe { - let idx = self.inner.wrap_add(self.inner.tail, idx); - self.inner.buffer_read(idx) - } - } } #[stable(feature = "rust1", since = "1.0.0")] -impl<T> DoubleEndedIterator for IntoIter<T> { +impl<T, A: Allocator> DoubleEndedIterator for IntoIter<T, A> { #[inline] fn next_back(&mut self) -> Option<T> { self.inner.pop_back() @@ -63,25 +52,14 @@ impl<T> DoubleEndedIterator for IntoIter<T> { } #[stable(feature = "rust1", since = "1.0.0")] -impl<T> ExactSizeIterator for IntoIter<T> { +impl<T, A: Allocator> ExactSizeIterator for IntoIter<T, A> { fn is_empty(&self) -> bool { self.inner.is_empty() } } #[stable(feature = "fused", since = "1.26.0")] -impl<T> FusedIterator for IntoIter<T> {} +impl<T, A: Allocator> FusedIterator for IntoIter<T, A> {} #[unstable(feature = "trusted_len", issue = "37572")] -unsafe impl<T> TrustedLen for IntoIter<T> {} - -#[doc(hidden)] -#[unstable(feature = "trusted_random_access", issue = "none")] -// T: Copy as approximation for !Drop since get_unchecked does not update the pointers -// and thus we can't implement drop-handling -unsafe impl<T> TrustedRandomAccess for IntoIter<T> -where - T: Copy, -{ - const MAY_HAVE_SIDE_EFFECT: bool = false; -} +unsafe impl<T, A: Allocator> TrustedLen for IntoIter<T, A> {} diff --git a/library/alloc/src/collections/vec_deque/iter.rs b/library/alloc/src/collections/vec_deque/iter.rs index f3eb228c9e3..edadd666edc 100644 --- a/library/alloc/src/collections/vec_deque/iter.rs +++ b/library/alloc/src/collections/vec_deque/iter.rs @@ -1,5 +1,5 @@ use core::fmt; -use core::iter::{FusedIterator, TrustedLen, TrustedRandomAccess}; +use core::iter::{FusedIterator, TrustedLen, TrustedRandomAccess, TrustedRandomAccessNoCoerce}; use core::ops::Try; use super::{count, wrap_index, RingSlices}; @@ -103,11 +103,9 @@ impl<'a, T> Iterator for Iter<'a, T> { } #[inline] - unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item - where - Self: TrustedRandomAccess, - { - // Safety: The TrustedRandomAccess contract requires that callers only pass an index + #[doc(hidden)] + unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item { + // Safety: The TrustedRandomAccess contract requires that callers only pass an index // that is in bounds. unsafe { let idx = wrap_index(self.tail.wrapping_add(idx), self.ring.len()); @@ -176,6 +174,10 @@ unsafe impl<T> TrustedLen for Iter<'_, T> {} #[doc(hidden)] #[unstable(feature = "trusted_random_access", issue = "none")] -unsafe impl<T> TrustedRandomAccess for Iter<'_, T> { +unsafe impl<T> TrustedRandomAccess for Iter<'_, T> {} + +#[doc(hidden)] +#[unstable(feature = "trusted_random_access", issue = "none")] +unsafe impl<T> TrustedRandomAccessNoCoerce for Iter<'_, T> { const MAY_HAVE_SIDE_EFFECT: bool = false; } diff --git a/library/alloc/src/collections/vec_deque/iter_mut.rs b/library/alloc/src/collections/vec_deque/iter_mut.rs index 9493676e66b..7700b31cf5b 100644 --- a/library/alloc/src/collections/vec_deque/iter_mut.rs +++ b/library/alloc/src/collections/vec_deque/iter_mut.rs @@ -1,5 +1,5 @@ use core::fmt; -use core::iter::{FusedIterator, TrustedLen, TrustedRandomAccess}; +use core::iter::{FusedIterator, TrustedLen, TrustedRandomAccess, TrustedRandomAccessNoCoerce}; use core::marker::PhantomData; use super::{count, wrap_index, RingSlices}; @@ -89,11 +89,9 @@ impl<'a, T> Iterator for IterMut<'a, T> { } #[inline] - unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item - where - Self: TrustedRandomAccess, - { - // Safety: The TrustedRandomAccess contract requires that callers only pass an index + #[doc(hidden)] + unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item { + // Safety: The TrustedRandomAccess contract requires that callers only pass an index // that is in bounds. unsafe { let idx = wrap_index(self.tail.wrapping_add(idx), self.ring.len()); @@ -145,6 +143,10 @@ unsafe impl<T> TrustedLen for IterMut<'_, T> {} #[doc(hidden)] #[unstable(feature = "trusted_random_access", issue = "none")] -unsafe impl<T> TrustedRandomAccess for IterMut<'_, T> { +unsafe impl<T> TrustedRandomAccess for IterMut<'_, T> {} + +#[doc(hidden)] +#[unstable(feature = "trusted_random_access", issue = "none")] +unsafe impl<T> TrustedRandomAccessNoCoerce for IterMut<'_, T> { const MAY_HAVE_SIDE_EFFECT: bool = false; } diff --git a/library/alloc/src/collections/vec_deque/macros.rs b/library/alloc/src/collections/vec_deque/macros.rs index 0d59d312cf4..5c7913073fe 100644 --- a/library/alloc/src/collections/vec_deque/macros.rs +++ b/library/alloc/src/collections/vec_deque/macros.rs @@ -1,9 +1,9 @@ macro_rules! __impl_slice_eq1 { ([$($vars:tt)*] $lhs:ty, $rhs:ty, $($constraints:tt)*) => { #[stable(feature = "vec_deque_partial_eq_slice", since = "1.17.0")] - impl<A, B, $($vars)*> PartialEq<$rhs> for $lhs + impl<T, U, A: Allocator, $($vars)*> PartialEq<$rhs> for $lhs where - A: PartialEq<B>, + T: PartialEq<U>, $($constraints)* { fn eq(&self, other: &$rhs) -> bool { diff --git a/library/alloc/src/collections/vec_deque/mod.rs b/library/alloc/src/collections/vec_deque/mod.rs index 5d03be35e46..9a2205420a1 100644 --- a/library/alloc/src/collections/vec_deque/mod.rs +++ b/library/alloc/src/collections/vec_deque/mod.rs @@ -17,7 +17,9 @@ use core::ops::{Index, IndexMut, Range, RangeBounds}; use core::ptr::{self, NonNull}; use core::slice; +use crate::alloc::{Allocator, Global}; use crate::collections::TryReserveError; +use crate::collections::TryReserveErrorKind; use crate::raw_vec::RawVec; use crate::vec::Vec; @@ -67,6 +69,14 @@ const MAXIMUM_ZST_CAPACITY: usize = 1 << (usize::BITS - 1); // Largest possible /// push onto the back in this manner, and iterating over `VecDeque` goes front /// to back. /// +/// A `VecDeque` with a known list of items can be initialized from an array: +/// +/// ``` +/// use std::collections::VecDeque; +/// +/// let deq = VecDeque::from([-1, 0, 1]); +/// ``` +/// /// Since `VecDeque` is a ring buffer, its elements are not necessarily contiguous /// in memory. If you want to access the elements as a single slice, such as for /// efficient sorting, you can use [`make_contiguous`]. It rotates the `VecDeque` @@ -80,7 +90,10 @@ const MAXIMUM_ZST_CAPACITY: usize = 1 << (usize::BITS - 1); // Largest possible /// [`make_contiguous`]: VecDeque::make_contiguous #[cfg_attr(not(test), rustc_diagnostic_item = "vecdeque_type")] #[stable(feature = "rust1", since = "1.0.0")] -pub struct VecDeque<T> { +pub struct VecDeque< + T, + #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, +> { // tail and head are pointers into the buffer. Tail always points // to the first element that could be read, Head always points // to where data should be written. @@ -88,13 +101,15 @@ pub struct VecDeque<T> { // is defined as the distance between the two. tail: usize, head: usize, - buf: RawVec<T>, + buf: RawVec<T, A>, } #[stable(feature = "rust1", since = "1.0.0")] -impl<T: Clone> Clone for VecDeque<T> { - fn clone(&self) -> VecDeque<T> { - self.iter().cloned().collect() +impl<T: Clone, A: Allocator + Clone> Clone for VecDeque<T, A> { + fn clone(&self) -> Self { + let mut deq = Self::with_capacity_in(self.len(), self.allocator().clone()); + deq.extend(self.iter().cloned()); + deq } fn clone_from(&mut self, other: &Self) { @@ -114,7 +129,7 @@ impl<T: Clone> Clone for VecDeque<T> { } #[stable(feature = "rust1", since = "1.0.0")] -unsafe impl<#[may_dangle] T> Drop for VecDeque<T> { +unsafe impl<#[may_dangle] T, A: Allocator> Drop for VecDeque<T, A> { fn drop(&mut self) { /// Runs the destructor for all items in the slice when it gets dropped (normally or /// during unwinding). @@ -147,7 +162,7 @@ impl<T> Default for VecDeque<T> { } } -impl<T> VecDeque<T> { +impl<T, A: Allocator> VecDeque<T, A> { /// Marginally more convenient #[inline] fn ptr(&self) -> *mut T { @@ -457,9 +472,10 @@ impl<T> VecDeque<T> { /// /// let vector: VecDeque<u32> = VecDeque::new(); /// ``` + #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn new() -> VecDeque<T> { - VecDeque::with_capacity(INITIAL_CAPACITY) + VecDeque::new_in(Global) } /// Creates an empty `VecDeque` with space for at least `capacity` elements. @@ -471,13 +487,45 @@ impl<T> VecDeque<T> { /// /// let vector: VecDeque<u32> = VecDeque::with_capacity(10); /// ``` + #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn with_capacity(capacity: usize) -> VecDeque<T> { + Self::with_capacity_in(capacity, Global) + } +} + +impl<T, A: Allocator> VecDeque<T, A> { + /// Creates an empty `VecDeque`. + /// + /// # Examples + /// + /// ``` + /// use std::collections::VecDeque; + /// + /// let vector: VecDeque<u32> = VecDeque::new(); + /// ``` + #[inline] + #[unstable(feature = "allocator_api", issue = "32838")] + pub fn new_in(alloc: A) -> VecDeque<T, A> { + VecDeque::with_capacity_in(INITIAL_CAPACITY, alloc) + } + + /// Creates an empty `VecDeque` with space for at least `capacity` elements. + /// + /// # Examples + /// + /// ``` + /// use std::collections::VecDeque; + /// + /// let vector: VecDeque<u32> = VecDeque::with_capacity(10); + /// ``` + #[unstable(feature = "allocator_api", issue = "32838")] + pub fn with_capacity_in(capacity: usize, alloc: A) -> VecDeque<T, A> { // +1 since the ringbuffer always leaves one space empty let cap = cmp::max(capacity + 1, MINIMUM_CAPACITY + 1).next_power_of_two(); assert!(cap > capacity, "capacity overflow"); - VecDeque { tail: 0, head: 0, buf: RawVec::with_capacity(cap) } + VecDeque { tail: 0, head: 0, buf: RawVec::with_capacity_in(cap, alloc) } } /// Provides a reference to the element at the given index. @@ -650,7 +698,9 @@ impl<T> VecDeque<T> { /// /// Note that the allocator may give the collection more space than it /// requests. Therefore, capacity can not be relied upon to be precisely - /// minimal. Prefer `reserve` if future insertions are expected. + /// minimal. Prefer [`reserve`] if future insertions are expected. + /// + /// [`reserve`]: VecDeque::reserve /// /// # Errors /// @@ -724,7 +774,7 @@ impl<T> VecDeque<T> { let new_cap = used_cap .checked_add(additional) .and_then(|needed_cap| needed_cap.checked_next_power_of_two()) - .ok_or(TryReserveError::CapacityOverflow)?; + .ok_or(TryReserveErrorKind::CapacityOverflow)?; if new_cap > old_cap { self.buf.try_reserve_exact(used_cap, new_cap - used_cap)?; @@ -766,7 +816,6 @@ impl<T> VecDeque<T> { /// # Examples /// /// ``` - /// #![feature(shrink_to)] /// use std::collections::VecDeque; /// /// let mut buf = VecDeque::with_capacity(15); @@ -777,7 +826,7 @@ impl<T> VecDeque<T> { /// buf.shrink_to(0); /// assert!(buf.capacity() >= 4); /// ``` - #[unstable(feature = "shrink_to", reason = "new API", issue = "56431")] + #[stable(feature = "shrink_to", since = "1.56.0")] pub fn shrink_to(&mut self, min_capacity: usize) { let min_capacity = cmp::min(min_capacity, self.capacity()); // We don't have to worry about an overflow as neither `self.len()` nor `self.capacity()` @@ -904,6 +953,13 @@ impl<T> VecDeque<T> { } } + /// Returns a reference to the underlying allocator. + #[unstable(feature = "allocator_api", issue = "32838")] + #[inline] + pub fn allocator(&self) -> &A { + self.buf.allocator() + } + /// Returns a front-to-back iterator. /// /// # Examples @@ -1036,7 +1092,6 @@ impl<T> VecDeque<T> { /// v.push_back(1); /// assert_eq!(v.len(), 1); /// ``` - #[doc(alias = "length")] #[stable(feature = "rust1", since = "1.0.0")] pub fn len(&self) -> usize { count(self.tail, self.head, self.cap()) @@ -1177,7 +1232,7 @@ impl<T> VecDeque<T> { /// ``` #[inline] #[stable(feature = "drain", since = "1.6.0")] - pub fn drain<R>(&mut self, range: R) -> Drain<'_, T> + pub fn drain<R>(&mut self, range: R) -> Drain<'_, T, A> where R: RangeBounds<usize>, { @@ -1966,12 +2021,15 @@ impl<T> VecDeque<T> { #[inline] #[must_use = "use `.truncate()` if you don't need the other half"] #[stable(feature = "split_off", since = "1.4.0")] - pub fn split_off(&mut self, at: usize) -> Self { + pub fn split_off(&mut self, at: usize) -> Self + where + A: Clone, + { let len = self.len(); assert!(at <= len, "`at` out of bounds"); let other_len = len - at; - let mut other = VecDeque::with_capacity(other_len); + let mut other = VecDeque::with_capacity_in(other_len, self.allocator().clone()); unsafe { let (first_half, second_half) = self.as_slices(); @@ -2051,7 +2109,8 @@ impl<T> VecDeque<T> { /// assert_eq!(buf, [2, 4]); /// ``` /// - /// The exact order may be useful for tracking external state, like an index. + /// Because the elements are visited exactly once in the original order, + /// external state may be used to decide which elements to keep. /// /// ``` /// use std::collections::VecDeque; @@ -2060,8 +2119,8 @@ impl<T> VecDeque<T> { /// buf.extend(1..6); /// /// let keep = [false, true, true, false, true]; - /// let mut i = 0; - /// buf.retain(|_| (keep[i], i += 1).0); + /// let mut iter = keep.iter(); + /// buf.retain(|_| *iter.next().unwrap()); /// assert_eq!(buf, [2, 3, 5]); /// ``` #[stable(feature = "vec_deque_retain", since = "1.4.0")] @@ -2594,7 +2653,7 @@ impl<T> VecDeque<T> { } } -impl<T: Clone> VecDeque<T> { +impl<T: Clone, A: Allocator> VecDeque<T, A> { /// Modifies the `VecDeque` in-place so that `len()` is equal to new_len, /// either by removing excess elements from the back or by appending clones of `value` /// to the back. @@ -2638,8 +2697,8 @@ fn count(tail: usize, head: usize, size: usize) -> usize { } #[stable(feature = "rust1", since = "1.0.0")] -impl<A: PartialEq> PartialEq for VecDeque<A> { - fn eq(&self, other: &VecDeque<A>) -> bool { +impl<T: PartialEq, A: Allocator> PartialEq for VecDeque<T, A> { + fn eq(&self, other: &Self) -> bool { if self.len() != other.len() { return false; } @@ -2677,32 +2736,32 @@ impl<A: PartialEq> PartialEq for VecDeque<A> { } #[stable(feature = "rust1", since = "1.0.0")] -impl<A: Eq> Eq for VecDeque<A> {} +impl<T: Eq, A: Allocator> Eq for VecDeque<T, A> {} -__impl_slice_eq1! { [] VecDeque<A>, Vec<B>, } -__impl_slice_eq1! { [] VecDeque<A>, &[B], } -__impl_slice_eq1! { [] VecDeque<A>, &mut [B], } -__impl_slice_eq1! { [const N: usize] VecDeque<A>, [B; N], } -__impl_slice_eq1! { [const N: usize] VecDeque<A>, &[B; N], } -__impl_slice_eq1! { [const N: usize] VecDeque<A>, &mut [B; N], } +__impl_slice_eq1! { [] VecDeque<T, A>, Vec<U, A>, } +__impl_slice_eq1! { [] VecDeque<T, A>, &[U], } +__impl_slice_eq1! { [] VecDeque<T, A>, &mut [U], } +__impl_slice_eq1! { [const N: usize] VecDeque<T, A>, [U; N], } +__impl_slice_eq1! { [const N: usize] VecDeque<T, A>, &[U; N], } +__impl_slice_eq1! { [const N: usize] VecDeque<T, A>, &mut [U; N], } #[stable(feature = "rust1", since = "1.0.0")] -impl<A: PartialOrd> PartialOrd for VecDeque<A> { - fn partial_cmp(&self, other: &VecDeque<A>) -> Option<Ordering> { +impl<T: PartialOrd, A: Allocator> PartialOrd for VecDeque<T, A> { + fn partial_cmp(&self, other: &Self) -> Option<Ordering> { self.iter().partial_cmp(other.iter()) } } #[stable(feature = "rust1", since = "1.0.0")] -impl<A: Ord> Ord for VecDeque<A> { +impl<T: Ord, A: Allocator> Ord for VecDeque<T, A> { #[inline] - fn cmp(&self, other: &VecDeque<A>) -> Ordering { + fn cmp(&self, other: &Self) -> Ordering { self.iter().cmp(other.iter()) } } #[stable(feature = "rust1", since = "1.0.0")] -impl<A: Hash> Hash for VecDeque<A> { +impl<T: Hash, A: Allocator> Hash for VecDeque<T, A> { fn hash<H: Hasher>(&self, state: &mut H) { self.len().hash(state); // It's not possible to use Hash::hash_slice on slices @@ -2716,26 +2775,26 @@ impl<A: Hash> Hash for VecDeque<A> { } #[stable(feature = "rust1", since = "1.0.0")] -impl<A> Index<usize> for VecDeque<A> { - type Output = A; +impl<T, A: Allocator> Index<usize> for VecDeque<T, A> { + type Output = T; #[inline] - fn index(&self, index: usize) -> &A { + fn index(&self, index: usize) -> &T { self.get(index).expect("Out of bounds access") } } #[stable(feature = "rust1", since = "1.0.0")] -impl<A> IndexMut<usize> for VecDeque<A> { +impl<T, A: Allocator> IndexMut<usize> for VecDeque<T, A> { #[inline] - fn index_mut(&mut self, index: usize) -> &mut A { + fn index_mut(&mut self, index: usize) -> &mut T { self.get_mut(index).expect("Out of bounds access") } } #[stable(feature = "rust1", since = "1.0.0")] -impl<A> FromIterator<A> for VecDeque<A> { - fn from_iter<T: IntoIterator<Item = A>>(iter: T) -> VecDeque<A> { +impl<T> FromIterator<T> for VecDeque<T> { + fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> VecDeque<T> { let iterator = iter.into_iter(); let (lower, _) = iterator.size_hint(); let mut deq = VecDeque::with_capacity(lower); @@ -2745,19 +2804,19 @@ impl<A> FromIterator<A> for VecDeque<A> { } #[stable(feature = "rust1", since = "1.0.0")] -impl<T> IntoIterator for VecDeque<T> { +impl<T, A: Allocator> IntoIterator for VecDeque<T, A> { type Item = T; - type IntoIter = IntoIter<T>; + type IntoIter = IntoIter<T, A>; /// Consumes the `VecDeque` into a front-to-back iterator yielding elements by /// value. - fn into_iter(self) -> IntoIter<T> { + fn into_iter(self) -> IntoIter<T, A> { IntoIter { inner: self } } } #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T> IntoIterator for &'a VecDeque<T> { +impl<'a, T, A: Allocator> IntoIterator for &'a VecDeque<T, A> { type Item = &'a T; type IntoIter = Iter<'a, T>; @@ -2767,7 +2826,7 @@ impl<'a, T> IntoIterator for &'a VecDeque<T> { } #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T> IntoIterator for &'a mut VecDeque<T> { +impl<'a, T, A: Allocator> IntoIterator for &'a mut VecDeque<T, A> { type Item = &'a mut T; type IntoIter = IterMut<'a, T>; @@ -2777,8 +2836,8 @@ impl<'a, T> IntoIterator for &'a mut VecDeque<T> { } #[stable(feature = "rust1", since = "1.0.0")] -impl<A> Extend<A> for VecDeque<A> { - fn extend<T: IntoIterator<Item = A>>(&mut self, iter: T) { +impl<T, A: Allocator> Extend<T> for VecDeque<T, A> { + fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) { // This function should be the moral equivalent of: // // for item in iter.into_iter() { @@ -2800,7 +2859,7 @@ impl<A> Extend<A> for VecDeque<A> { } #[inline] - fn extend_one(&mut self, elem: A) { + fn extend_one(&mut self, elem: T) { self.push_back(elem); } @@ -2811,7 +2870,7 @@ impl<A> Extend<A> for VecDeque<A> { } #[stable(feature = "extend_ref", since = "1.2.0")] -impl<'a, T: 'a + Copy> Extend<&'a T> for VecDeque<T> { +impl<'a, T: 'a + Copy, A: Allocator> Extend<&'a T> for VecDeque<T, A> { fn extend<I: IntoIterator<Item = &'a T>>(&mut self, iter: I) { self.extend(iter.into_iter().cloned()); } @@ -2828,14 +2887,14 @@ impl<'a, T: 'a + Copy> Extend<&'a T> for VecDeque<T> { } #[stable(feature = "rust1", since = "1.0.0")] -impl<T: fmt::Debug> fmt::Debug for VecDeque<T> { +impl<T: fmt::Debug, A: Allocator> fmt::Debug for VecDeque<T, A> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_list().entries(self).finish() } } #[stable(feature = "vecdeque_vec_conversions", since = "1.10.0")] -impl<T> From<Vec<T>> for VecDeque<T> { +impl<T, A: Allocator> From<Vec<T, A>> for VecDeque<T, A> { /// Turn a [`Vec<T>`] into a [`VecDeque<T>`]. /// /// [`Vec<T>`]: crate::vec::Vec @@ -2844,7 +2903,7 @@ impl<T> From<Vec<T>> for VecDeque<T> { /// This avoids reallocating where possible, but the conditions for that are /// strict, and subject to change, and so shouldn't be relied upon unless the /// `Vec<T>` came from `From<VecDeque<T>>` and hasn't been reallocated. - fn from(mut other: Vec<T>) -> Self { + fn from(mut other: Vec<T, A>) -> Self { let len = other.len(); if mem::size_of::<T>() == 0 { // There's no actual allocation for ZSTs to worry about capacity, @@ -2862,15 +2921,15 @@ impl<T> From<Vec<T>> for VecDeque<T> { } unsafe { - let (other_buf, len, capacity) = other.into_raw_parts(); - let buf = RawVec::from_raw_parts(other_buf, capacity); + let (other_buf, len, capacity, alloc) = other.into_raw_parts_with_alloc(); + let buf = RawVec::from_raw_parts_in(other_buf, capacity, alloc); VecDeque { tail: 0, head: len, buf } } } } #[stable(feature = "vecdeque_vec_conversions", since = "1.10.0")] -impl<T> From<VecDeque<T>> for Vec<T> { +impl<T, A: Allocator> From<VecDeque<T, A>> for Vec<T, A> { /// Turn a [`VecDeque<T>`] into a [`Vec<T>`]. /// /// [`Vec<T>`]: crate::vec::Vec @@ -2900,7 +2959,7 @@ impl<T> From<VecDeque<T>> for Vec<T> { /// assert_eq!(vec, [8, 9, 1, 2, 3, 4]); /// assert_eq!(vec.as_ptr(), ptr); /// ``` - fn from(mut other: VecDeque<T>) -> Self { + fn from(mut other: VecDeque<T, A>) -> Self { other.make_contiguous(); unsafe { @@ -2908,11 +2967,26 @@ impl<T> From<VecDeque<T>> for Vec<T> { let buf = other.buf.ptr(); let len = other.len(); let cap = other.cap(); + let alloc = ptr::read(other.allocator()); if other.tail != 0 { ptr::copy(buf.add(other.tail), buf, len); } - Vec::from_raw_parts(buf, len, cap) + Vec::from_raw_parts_in(buf, len, cap, alloc) } } } + +#[stable(feature = "std_collections_from_array", since = "1.56.0")] +impl<T, const N: usize> From<[T; N]> for VecDeque<T> { + /// ``` + /// use std::collections::VecDeque; + /// + /// let deq1 = VecDeque::from([1, 2, 3, 4]); + /// let deq2: VecDeque<_> = [1, 2, 3, 4].into(); + /// assert_eq!(deq1, deq2); + /// ``` + fn from(arr: [T; N]) -> Self { + core::array::IntoIter::new(arr).collect() + } +} diff --git a/library/alloc/src/collections/vec_deque/pair_slices.rs b/library/alloc/src/collections/vec_deque/pair_slices.rs index 7b87090fb07..8e3ac9cfd1d 100644 --- a/library/alloc/src/collections/vec_deque/pair_slices.rs +++ b/library/alloc/src/collections/vec_deque/pair_slices.rs @@ -1,6 +1,8 @@ use core::cmp::{self}; use core::mem::replace; +use crate::alloc::Allocator; + use super::VecDeque; /// PairSlices pairs up equal length slice parts of two deques @@ -25,7 +27,7 @@ pub struct PairSlices<'a, 'b, T> { } impl<'a, 'b, T> PairSlices<'a, 'b, T> { - pub fn from(to: &'a mut VecDeque<T>, from: &'b VecDeque<T>) -> Self { + pub fn from<A: Allocator>(to: &'a mut VecDeque<T, A>, from: &'b VecDeque<T, A>) -> Self { let (a0, a1) = to.as_mut_slices(); let (b0, b1) = from.as_slices(); PairSlices { a0, a1, b0, b1 } diff --git a/library/alloc/src/fmt.rs b/library/alloc/src/fmt.rs index fd5ee189fbf..8c5125d2082 100644 --- a/library/alloc/src/fmt.rs +++ b/library/alloc/src/fmt.rs @@ -138,7 +138,7 @@ //! the `0` flag (see below) is specified for numerics, then the implicit fill character is //! `0`. //! -//! Note that alignment may not be implemented by some types. In particular, it +//! Note that alignment might not be implemented by some types. In particular, it //! is not generally implemented for the `Debug` trait. A good way to ensure //! padding is applied is to format your input, then pad this resulting string //! to obtain your output: @@ -300,7 +300,7 @@ //! count := parameter | integer //! parameter := argument '$' //! ``` -//! In the above grammar, `text` may not contain any `'{'` or `'}'` characters. +//! In the above grammar, `text` must not contain any `'{'` or `'}'` characters. //! //! # Formatting traits //! diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index a04e7c8a498..1a387f291cc 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -56,6 +56,10 @@ //! [`Rc`]: rc //! [`RefCell`]: core::cell +// To run liballoc tests without x.py without ending up with two copies of liballoc, Miri needs to be +// able to "empty" this crate. See <https://github.com/rust-lang/miri-test-libstd/issues/4>. +// rustc itself never sets the feature, so this line has no affect there. +#![cfg(any(not(feature = "miri-test-libstd"), test, doctest))] #![allow(unused_attributes)] #![stable(feature = "alloc", since = "1.36.0")] #![doc( @@ -81,6 +85,7 @@ #![feature(allow_internal_unstable)] #![feature(arbitrary_self_types)] #![feature(async_stream)] +#![cfg_attr(bootstrap, feature(bindings_after_at))] #![feature(box_patterns)] #![feature(box_syntax)] #![feature(cfg_sanitize)] @@ -90,6 +95,7 @@ #![feature(const_fn_trait_bound)] #![feature(cow_is_borrowed)] #![feature(const_cow_is_borrowed)] +#![feature(const_trait_impl)] #![feature(destructuring_assignment)] #![feature(dispatch_from_dyn)] #![feature(core_intrinsics)] @@ -109,7 +115,6 @@ #![feature(iter_zip)] #![feature(lang_items)] #![feature(layout_for_ptr)] -#![feature(maybe_uninit_ref)] #![feature(negative_impls)] #![feature(never_type)] #![feature(nll)] @@ -137,13 +142,12 @@ #![feature(maybe_uninit_extra, maybe_uninit_slice, maybe_uninit_uninit_array)] #![feature(alloc_layout_extra)] #![feature(trusted_random_access)] -#![cfg_attr(bootstrap, feature(try_trait))] -#![cfg_attr(not(bootstrap), feature(try_trait_v2))] -#![feature(min_type_alias_impl_trait)] +#![feature(try_trait_v2)] +#![cfg_attr(bootstrap, feature(min_type_alias_impl_trait))] +#![cfg_attr(not(bootstrap), feature(type_alias_impl_trait))] #![feature(associated_type_bounds)] #![feature(slice_group_by)] #![feature(decl_macro)] -#![feature(bindings_after_at)] // Allow testing this library #[cfg(test)] diff --git a/library/alloc/src/macros.rs b/library/alloc/src/macros.rs index 6a64587a223..189da9f0639 100644 --- a/library/alloc/src/macros.rs +++ b/library/alloc/src/macros.rs @@ -35,8 +35,6 @@ /// /// [`Vec`]: crate::vec::Vec #[cfg(not(test))] -#[doc(alias = "alloc")] -#[doc(alias = "malloc")] #[macro_export] #[stable(feature = "rust1", since = "1.0.0")] #[allow_internal_unstable(box_syntax, liballoc_internals)] diff --git a/library/alloc/src/raw_vec.rs b/library/alloc/src/raw_vec.rs index 2e2c9b76bd4..3caada06f6b 100644 --- a/library/alloc/src/raw_vec.rs +++ b/library/alloc/src/raw_vec.rs @@ -13,7 +13,8 @@ use core::slice; use crate::alloc::handle_alloc_error; use crate::alloc::{Allocator, Global, Layout}; use crate::boxed::Box; -use crate::collections::TryReserveError::{self, *}; +use crate::collections::TryReserveError; +use crate::collections::TryReserveErrorKind::*; #[cfg(test)] mod tests; @@ -425,7 +426,7 @@ impl<T, A: Allocator> RawVec<T, A> { if mem::size_of::<T>() == 0 { // Since we return a capacity of `usize::MAX` when `elem_size` is // 0, getting to here necessarily means the `RawVec` is overfull. - return Err(CapacityOverflow); + return Err(CapacityOverflow.into()); } // Nothing we can really do about these checks, sadly. @@ -451,7 +452,7 @@ impl<T, A: Allocator> RawVec<T, A> { if mem::size_of::<T>() == 0 { // Since we return a capacity of `usize::MAX` when the type size is // 0, getting to here necessarily means the `RawVec` is overfull. - return Err(CapacityOverflow); + return Err(CapacityOverflow.into()); } let cap = len.checked_add(additional).ok_or(CapacityOverflow)?; @@ -463,7 +464,6 @@ impl<T, A: Allocator> RawVec<T, A> { Ok(()) } - #[cfg(not(no_global_oom_handling))] fn shrink(&mut self, amount: usize) -> Result<(), TryReserveError> { assert!(amount <= self.capacity(), "Tried to shrink to a larger capacity"); @@ -472,10 +472,9 @@ impl<T, A: Allocator> RawVec<T, A> { let ptr = unsafe { let new_layout = Layout::from_size_align_unchecked(new_size, layout.align()); - self.alloc.shrink(ptr, layout, new_layout).map_err(|_| TryReserveError::AllocError { - layout: new_layout, - non_exhaustive: (), - })? + self.alloc + .shrink(ptr, layout, new_layout) + .map_err(|_| AllocError { layout: new_layout, non_exhaustive: () })? }; self.set_ptr(ptr); Ok(()) @@ -511,7 +510,7 @@ where alloc.allocate(new_layout) }; - memory.map_err(|_| AllocError { layout: new_layout, non_exhaustive: () }) + memory.map_err(|_| AllocError { layout: new_layout, non_exhaustive: () }.into()) } unsafe impl<#[may_dangle] T, A: Allocator> Drop for RawVec<T, A> { @@ -527,7 +526,7 @@ unsafe impl<#[may_dangle] T, A: Allocator> Drop for RawVec<T, A> { #[cfg(not(no_global_oom_handling))] #[inline] fn handle_reserve(result: Result<(), TryReserveError>) { - match result { + match result.map_err(|e| e.kind()) { Err(CapacityOverflow) => capacity_overflow(), Err(AllocError { layout, .. }) => handle_alloc_error(layout), Ok(()) => { /* yay */ } @@ -546,7 +545,7 @@ fn handle_reserve(result: Result<(), TryReserveError>) { #[inline] fn alloc_guard(alloc_size: usize) -> Result<(), TryReserveError> { if usize::BITS < 64 && alloc_size > isize::MAX as usize { - Err(CapacityOverflow) + Err(CapacityOverflow.into()) } else { Ok(()) } diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index f131182a896..0b3079fa59d 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -262,6 +262,8 @@ use core::marker::{self, PhantomData, Unpin, Unsize}; use core::mem::size_of_val; use core::mem::{self, align_of_val_raw, forget}; use core::ops::{CoerceUnsized, Deref, DispatchFromDyn, Receiver}; +use core::panic::{RefUnwindSafe, UnwindSafe}; +#[cfg(not(no_global_oom_handling))] use core::pin::Pin; use core::ptr::{self, NonNull}; #[cfg(not(no_global_oom_handling))] @@ -313,6 +315,9 @@ impl<T: ?Sized> !marker::Send for Rc<T> {} #[stable(feature = "rust1", since = "1.0.0")] impl<T: ?Sized> !marker::Sync for Rc<T> {} +#[stable(feature = "catch_unwind", since = "1.9.0")] +impl<T: RefUnwindSafe + ?Sized> UnwindSafe for Rc<T> {} + #[unstable(feature = "coerce_unsized", issue = "27732")] impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<Rc<U>> for Rc<T> {} @@ -346,6 +351,7 @@ impl<T> Rc<T> { /// /// let five = Rc::new(5); /// ``` + #[cfg(not(no_global_oom_handling))] #[stable(feature = "rust1", since = "1.0.0")] pub fn new(value: T) -> Rc<T> { // There is an implicit weak pointer owned by all the strong @@ -381,6 +387,7 @@ impl<T> Rc<T> { /// } /// } /// ``` + #[cfg(not(no_global_oom_handling))] #[unstable(feature = "arc_new_cyclic", issue = "75861")] pub fn new_cyclic(data_fn: impl FnOnce(&Weak<T>) -> T) -> Rc<T> { // Construct the inner in the "uninitialized" state with a single @@ -577,6 +584,7 @@ impl<T> Rc<T> { } /// Constructs a new `Pin<Rc<T>>`. If `T` does not implement `Unpin`, then /// `value` will be pinned in memory and unable to be moved. + #[cfg(not(no_global_oom_handling))] #[stable(feature = "pin", since = "1.33.0")] pub fn pin(value: T) -> Pin<Rc<T>> { unsafe { Pin::new_unchecked(Rc::new(value)) } @@ -1473,6 +1481,7 @@ impl<T: ?Sized> Clone for Rc<T> { } } +#[cfg(not(no_global_oom_handling))] #[stable(feature = "rust1", since = "1.0.0")] impl<T: Default> Default for Rc<T> { /// Creates a new `Rc<T>`, with the `Default` value for `T`. @@ -1731,6 +1740,7 @@ impl<T: ?Sized> fmt::Pointer for Rc<T> { } } +#[cfg(not(no_global_oom_handling))] #[stable(feature = "from_for_ptrs", since = "1.6.0")] impl<T> From<T> for Rc<T> { /// Converts a generic type `T` into a `Rc<T>` @@ -2520,7 +2530,7 @@ unsafe fn data_offset<T: ?Sized>(ptr: *const T) -> isize { // SAFETY: since the only unsized types possible are slices, trait objects, // and extern types, the input safety requirement is currently enough to // satisfy the requirements of align_of_val_raw; this is an implementation - // detail of the language that may not be relied upon outside of std. + // detail of the language that must not be relied upon outside of std. unsafe { data_offset_align(align_of_val_raw(ptr)) } } diff --git a/library/alloc/src/slice.rs b/library/alloc/src/slice.rs index dcd64899204..4c8ea6902ff 100644 --- a/library/alloc/src/slice.rs +++ b/library/alloc/src/slice.rs @@ -1042,7 +1042,7 @@ where } /// This merge sort borrows some (but not all) ideas from TimSort, which is described in detail -/// [here](http://svn.python.org/projects/python/trunk/Objects/listsort.txt). +/// [here](https://github.com/python/cpython/blob/main/Objects/listsort.txt). /// /// The algorithm identifies strictly descending and non-descending subsequences, which are called /// natural runs. There is a stack of pending runs yet to be merged. Each newly found run is pushed diff --git a/library/alloc/src/str.rs b/library/alloc/src/str.rs index 57279e81a95..62ba2e57655 100644 --- a/library/alloc/src/str.rs +++ b/library/alloc/src/str.rs @@ -396,7 +396,7 @@ impl str { return s; fn map_uppercase_sigma(from: &str, i: usize, to: &mut String) { - // See http://www.unicode.org/versions/Unicode7.0.0/ch03.pdf#G33992 + // See https://www.unicode.org/versions/Unicode7.0.0/ch03.pdf#G33992 // for the definition of `Final_Sigma`. debug_assert!('Σ'.len_utf8() == 2); let is_word_final = case_ignoreable_then_cased(from[..i].chars().rev()) diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs index dbe5bc1da46..6568d9f9907 100644 --- a/library/alloc/src/string.rs +++ b/library/alloc/src/string.rs @@ -48,7 +48,7 @@ use core::fmt; use core::hash; #[cfg(not(no_global_oom_handling))] use core::iter::FromIterator; -use core::iter::FusedIterator; +use core::iter::{from_fn, FusedIterator}; #[cfg(not(no_global_oom_handling))] use core::ops::Add; #[cfg(not(no_global_oom_handling))] @@ -419,8 +419,6 @@ impl String { /// ``` #[cfg(not(no_global_oom_handling))] #[inline] - #[doc(alias = "alloc")] - #[doc(alias = "malloc")] #[stable(feature = "rust1", since = "1.0.0")] pub fn with_capacity(capacity: usize) -> String { String { vec: Vec::with_capacity(capacity) } @@ -923,7 +921,7 @@ impl String { /// assert!(s.capacity() >= 10); /// ``` /// - /// This may not actually increase the capacity: + /// This might not actually increase the capacity: /// /// ``` /// let mut s = String::with_capacity(10); @@ -971,7 +969,7 @@ impl String { /// assert!(s.capacity() >= 10); /// ``` /// - /// This may not actually increase the capacity: + /// This might not actually increase the capacity: /// /// ``` /// let mut s = String::with_capacity(10); @@ -1037,7 +1035,9 @@ impl String { /// /// Note that the allocator may give the collection more space than it /// requests. Therefore, capacity can not be relied upon to be precisely - /// minimal. Prefer `reserve` if future insertions are expected. + /// minimal. Prefer [`reserve`] if future insertions are expected. + /// + /// [`reserve`]: String::reserve /// /// # Errors /// @@ -1100,7 +1100,6 @@ impl String { /// # Examples /// /// ``` - /// #![feature(shrink_to)] /// let mut s = String::from("foo"); /// /// s.reserve(100); @@ -1113,7 +1112,7 @@ impl String { /// ``` #[cfg(not(no_global_oom_handling))] #[inline] - #[unstable(feature = "shrink_to", reason = "new API", issue = "56431")] + #[stable(feature = "shrink_to", since = "1.56.0")] pub fn shrink_to(&mut self, min_capacity: usize) { self.vec.shrink_to(min_capacity) } @@ -1290,32 +1289,49 @@ impl String { { use core::str::pattern::Searcher; - let matches = { + let rejections = { let mut searcher = pat.into_searcher(self); - let mut matches = Vec::new(); - - while let Some(m) = searcher.next_match() { - matches.push(m); - } - - matches + // Per Searcher::next: + // + // A Match result needs to contain the whole matched pattern, + // however Reject results may be split up into arbitrary many + // adjacent fragments. Both ranges may have zero length. + // + // In practice the implementation of Searcher::next_match tends to + // be more efficient, so we use it here and do some work to invert + // matches into rejections since that's what we want to copy below. + let mut front = 0; + let rejections: Vec<_> = from_fn(|| { + let (start, end) = searcher.next_match()?; + let prev_front = front; + front = end; + Some((prev_front, start)) + }) + .collect(); + rejections.into_iter().chain(core::iter::once((front, self.len()))) }; - let len = self.len(); - let mut shrunk_by = 0; + let mut len = 0; + let ptr = self.vec.as_mut_ptr(); + + for (start, end) in rejections { + let count = end - start; + if start != len { + // SAFETY: per Searcher::next: + // + // The stream of Match and Reject values up to a Done will + // contain index ranges that are adjacent, non-overlapping, + // covering the whole haystack, and laying on utf8 + // boundaries. + unsafe { + ptr::copy(ptr.add(start), ptr.add(len), count); + } + } + len += count; + } - // SAFETY: start and end will be on utf8 byte boundaries per - // the Searcher docs unsafe { - for (start, end) in matches { - ptr::copy( - self.vec.as_mut_ptr().add(end - shrunk_by), - self.vec.as_mut_ptr().add(start - shrunk_by), - len - end, - ); - shrunk_by += end - start; - } - self.vec.set_len(len - shrunk_by); + self.vec.set_len(len); } } @@ -1335,13 +1351,14 @@ impl String { /// assert_eq!(s, "foobar"); /// ``` /// - /// The exact order may be useful for tracking external state, like an index. + /// Because the elements are visited exactly once in the original order, + /// external state may be used to decide which elements to keep. /// /// ``` /// let mut s = String::from("abcde"); /// let keep = [false, true, true, false, true]; - /// let mut i = 0; - /// s.retain(|_| (keep[i], i += 1).0); + /// let mut iter = keep.iter(); + /// s.retain(|_| *iter.next().unwrap()); /// assert_eq!(s, "bce"); /// ``` #[inline] @@ -1434,7 +1451,7 @@ impl String { unsafe { ptr::copy(self.vec.as_ptr().add(idx), self.vec.as_mut_ptr().add(idx + amt), len - idx); - ptr::copy(bytes.as_ptr(), self.vec.as_mut_ptr().add(idx), amt); + ptr::copy_nonoverlapping(bytes.as_ptr(), self.vec.as_mut_ptr().add(idx), amt); self.vec.set_len(len + amt); } } @@ -1502,7 +1519,7 @@ impl String { } /// Returns the length of this `String`, in bytes, not [`char`]s or - /// graphemes. In other words, it may not be what a human considers the + /// graphemes. In other words, it might not be what a human considers the /// length of the string. /// /// # Examples @@ -1517,7 +1534,6 @@ impl String { /// assert_eq!(fancy_f.len(), 4); /// assert_eq!(fancy_f.chars().count(), 3); /// ``` - #[doc(alias = "length")] #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn len(&self) -> usize { @@ -2089,7 +2105,8 @@ impl_eq! { Cow<'a, str>, &'b str } impl_eq! { Cow<'a, str>, String } #[stable(feature = "rust1", since = "1.0.0")] -impl Default for String { +#[rustc_const_unstable(feature = "const_default_impls", issue = "87864")] +impl const Default for String { /// Creates an empty `String`. #[inline] fn default() -> String { @@ -2474,6 +2491,9 @@ impl AsRef<[u8]> for String { #[cfg(not(no_global_oom_handling))] #[stable(feature = "rust1", since = "1.0.0")] impl From<&str> for String { + /// Converts a `&str` into a [`String`]. + /// + /// The result is allocated on the heap. #[inline] fn from(s: &str) -> String { s.to_owned() @@ -2483,7 +2503,7 @@ impl From<&str> for String { #[cfg(not(no_global_oom_handling))] #[stable(feature = "from_mut_str_for_string", since = "1.44.0")] impl From<&mut str> for String { - /// Converts a `&mut str` into a `String`. + /// Converts a `&mut str` into a [`String`]. /// /// The result is allocated on the heap. #[inline] @@ -2495,6 +2515,9 @@ impl From<&mut str> for String { #[cfg(not(no_global_oom_handling))] #[stable(feature = "from_ref_string", since = "1.35.0")] impl From<&String> for String { + /// Converts a `&String` into a [`String`]. + /// + /// This clones `s` and returns the clone. #[inline] fn from(s: &String) -> String { s.clone() @@ -2505,7 +2528,7 @@ impl From<&String> for String { #[cfg(not(test))] #[stable(feature = "string_from_box", since = "1.18.0")] impl From<Box<str>> for String { - /// Converts the given boxed `str` slice to a `String`. + /// Converts the given boxed `str` slice to a [`String`]. /// It is notable that the `str` slice is owned. /// /// # Examples @@ -2527,7 +2550,7 @@ impl From<Box<str>> for String { #[cfg(not(no_global_oom_handling))] #[stable(feature = "box_from_str", since = "1.20.0")] impl From<String> for Box<str> { - /// Converts the given `String` to a boxed `str` slice that is owned. + /// Converts the given [`String`] to a boxed `str` slice that is owned. /// /// # Examples /// @@ -2548,6 +2571,22 @@ impl From<String> for Box<str> { #[cfg(not(no_global_oom_handling))] #[stable(feature = "string_from_cow_str", since = "1.14.0")] impl<'a> From<Cow<'a, str>> for String { + /// Converts a clone-on-write string to an owned + /// instance of [`String`]. + /// + /// This extracts the owned string, + /// clones the string if it is not already owned. + /// + /// # Example + /// + /// ``` + /// # use std::borrow::Cow; + /// // If the string is not owned... + /// let cow: Cow<str> = Cow::Borrowed("eggplant"); + /// // It will allocate on the heap and copy the string. + /// let owned: String = String::from(cow); + /// assert_eq!(&owned[..], "eggplant"); + /// ``` fn from(s: Cow<'a, str>) -> String { s.into_owned() } @@ -2556,7 +2595,7 @@ impl<'a> From<Cow<'a, str>> for String { #[cfg(not(no_global_oom_handling))] #[stable(feature = "rust1", since = "1.0.0")] impl<'a> From<&'a str> for Cow<'a, str> { - /// Converts a string slice into a Borrowed variant. + /// Converts a string slice into a [`Borrowed`] variant. /// No heap allocation is performed, and the string /// is not copied. /// @@ -2566,6 +2605,8 @@ impl<'a> From<&'a str> for Cow<'a, str> { /// # use std::borrow::Cow; /// assert_eq!(Cow::from("eggplant"), Cow::Borrowed("eggplant")); /// ``` + /// + /// [`Borrowed`]: crate::borrow::Cow::Borrowed #[inline] fn from(s: &'a str) -> Cow<'a, str> { Cow::Borrowed(s) @@ -2575,7 +2616,7 @@ impl<'a> From<&'a str> for Cow<'a, str> { #[cfg(not(no_global_oom_handling))] #[stable(feature = "rust1", since = "1.0.0")] impl<'a> From<String> for Cow<'a, str> { - /// Converts a String into an Owned variant. + /// Converts a [`String`] into an [`Owned`] variant. /// No heap allocation is performed, and the string /// is not copied. /// @@ -2587,6 +2628,8 @@ impl<'a> From<String> for Cow<'a, str> { /// let s2 = "eggplant".to_string(); /// assert_eq!(Cow::from(s), Cow::<'static, str>::Owned(s2)); /// ``` + /// + /// [`Owned`]: crate::borrow::Cow::Owned #[inline] fn from(s: String) -> Cow<'a, str> { Cow::Owned(s) @@ -2596,7 +2639,7 @@ impl<'a> From<String> for Cow<'a, str> { #[cfg(not(no_global_oom_handling))] #[stable(feature = "cow_from_string_ref", since = "1.28.0")] impl<'a> From<&'a String> for Cow<'a, str> { - /// Converts a String reference into a Borrowed variant. + /// Converts a [`String`] reference into a [`Borrowed`] variant. /// No heap allocation is performed, and the string /// is not copied. /// @@ -2607,6 +2650,8 @@ impl<'a> From<&'a String> for Cow<'a, str> { /// let s = "eggplant".to_string(); /// assert_eq!(Cow::from(&s), Cow::Borrowed("eggplant")); /// ``` + /// + /// [`Borrowed`]: crate::borrow::Cow::Borrowed #[inline] fn from(s: &'a String) -> Cow<'a, str> { Cow::Borrowed(s.as_str()) @@ -2639,7 +2684,7 @@ impl<'a> FromIterator<String> for Cow<'a, str> { #[stable(feature = "from_string_for_vec_u8", since = "1.14.0")] impl From<String> for Vec<u8> { - /// Converts the given `String` to a vector `Vec` that holds values of type `u8`. + /// Converts the given [`String`] to a vector [`Vec`] that holds values of type [`u8`]. /// /// # Examples /// @@ -2724,33 +2769,31 @@ impl<'a> Drain<'a> { /// # Examples /// /// ``` - /// #![feature(string_drain_as_str)] /// let mut s = String::from("abc"); /// let mut drain = s.drain(..); /// assert_eq!(drain.as_str(), "abc"); /// let _ = drain.next().unwrap(); /// assert_eq!(drain.as_str(), "bc"); /// ``` - #[unstable(feature = "string_drain_as_str", issue = "76905")] // Note: uncomment AsRef impls below when stabilizing. + #[stable(feature = "string_drain_as_str", since = "1.55.0")] pub fn as_str(&self) -> &str { self.iter.as_str() } } -// Uncomment when stabilizing `string_drain_as_str`. -// #[unstable(feature = "string_drain_as_str", issue = "76905")] -// impl<'a> AsRef<str> for Drain<'a> { -// fn as_ref(&self) -> &str { -// self.as_str() -// } -// } -// -// #[unstable(feature = "string_drain_as_str", issue = "76905")] -// impl<'a> AsRef<[u8]> for Drain<'a> { -// fn as_ref(&self) -> &[u8] { -// self.as_str().as_bytes() -// } -// } +#[stable(feature = "string_drain_as_str", since = "1.55.0")] +impl<'a> AsRef<str> for Drain<'a> { + fn as_ref(&self) -> &str { + self.as_str() + } +} + +#[stable(feature = "string_drain_as_str", since = "1.55.0")] +impl<'a> AsRef<[u8]> for Drain<'a> { + fn as_ref(&self) -> &[u8] { + self.as_str().as_bytes() + } +} #[stable(feature = "drain", since = "1.6.0")] impl Iterator for Drain<'_> { @@ -2785,6 +2828,14 @@ impl FusedIterator for Drain<'_> {} #[cfg(not(no_global_oom_handling))] #[stable(feature = "from_char_for_string", since = "1.46.0")] impl From<char> for String { + /// Allocates an owned [`String`] from a single character. + /// + /// # Example + /// ```rust + /// let c: char = 'a'; + /// let s: String = String::from(c); + /// assert_eq!("a", &s[..]); + /// ``` #[inline] fn from(c: char) -> Self { c.to_string() diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index a8fa028fc90..3183a6db410 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -19,6 +19,7 @@ use core::marker::{PhantomData, Unpin, Unsize}; use core::mem::size_of_val; use core::mem::{self, align_of_val_raw}; use core::ops::{CoerceUnsized, Deref, DispatchFromDyn, Receiver}; +use core::panic::{RefUnwindSafe, UnwindSafe}; use core::pin::Pin; use core::ptr::{self, NonNull}; #[cfg(not(no_global_oom_handling))] @@ -240,6 +241,9 @@ unsafe impl<T: ?Sized + Sync + Send> Send for Arc<T> {} #[stable(feature = "rust1", since = "1.0.0")] unsafe impl<T: ?Sized + Sync + Send> Sync for Arc<T> {} +#[stable(feature = "catch_unwind", since = "1.9.0")] +impl<T: RefUnwindSafe + ?Sized> UnwindSafe for Arc<T> {} + #[unstable(feature = "coerce_unsized", issue = "27732")] impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<Arc<U>> for Arc<T> {} @@ -332,6 +336,7 @@ impl<T> Arc<T> { /// /// let five = Arc::new(5); /// ``` + #[cfg(not(no_global_oom_handling))] #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn new(data: T) -> Arc<T> { @@ -365,6 +370,7 @@ impl<T> Arc<T> { /// me: me.clone(), /// }); /// ``` + #[cfg(not(no_global_oom_handling))] #[inline] #[unstable(feature = "arc_new_cyclic", issue = "75861")] pub fn new_cyclic(data_fn: impl FnOnce(&Weak<T>) -> T) -> Arc<T> { @@ -485,11 +491,19 @@ impl<T> Arc<T> { /// Constructs a new `Pin<Arc<T>>`. If `T` does not implement `Unpin`, then /// `data` will be pinned in memory and unable to be moved. + #[cfg(not(no_global_oom_handling))] #[stable(feature = "pin", since = "1.33.0")] pub fn pin(data: T) -> Pin<Arc<T>> { unsafe { Pin::new_unchecked(Arc::new(data)) } } + /// Constructs a new `Pin<Arc<T>>`, return an error if allocation fails. + #[unstable(feature = "allocator_api", issue = "32838")] + #[inline] + pub fn try_pin(data: T) -> Result<Pin<Arc<T>>, AllocError> { + unsafe { Ok(Pin::new_unchecked(Arc::try_new(data)?)) } + } + /// Constructs a new `Arc<T>`, returning an error if allocation fails. /// /// # Examples @@ -1046,8 +1060,8 @@ impl<T: ?Sized> Arc<T> { // Non-inlined part of `drop`. #[inline(never)] unsafe fn drop_slow(&mut self) { - // Destroy the data at this time, even though we may not free the box - // allocation itself (there may still be weak pointers lying around). + // Destroy the data at this time, even though we must not free the box + // allocation itself (there might still be weak pointers lying around). unsafe { ptr::drop_in_place(Self::get_mut_unchecked(self)) }; // Drop the weak ref collectively held by all strong references @@ -2274,6 +2288,7 @@ impl<T: ?Sized> fmt::Pointer for Arc<T> { } } +#[cfg(not(no_global_oom_handling))] #[stable(feature = "rust1", since = "1.0.0")] impl<T: Default> Default for Arc<T> { /// Creates a new `Arc<T>`, with the `Default` value for `T`. @@ -2298,8 +2313,23 @@ impl<T: ?Sized + Hash> Hash for Arc<T> { } } +#[cfg(not(no_global_oom_handling))] #[stable(feature = "from_for_ptrs", since = "1.6.0")] impl<T> From<T> for Arc<T> { + /// Converts a `T` into an `Arc<T>` + /// + /// The conversion moves the value into a + /// newly allocated `Arc`. It is equivalent to + /// calling `Arc::new(t)`. + /// + /// # Example + /// ```rust + /// # use std::sync::Arc; + /// let x = 5; + /// let arc = Arc::new(5); + /// + /// assert_eq!(Arc::from(x), arc); + /// ``` fn from(t: T) -> Self { Arc::new(t) } @@ -2561,7 +2591,7 @@ unsafe fn data_offset<T: ?Sized>(ptr: *const T) -> isize { // SAFETY: since the only unsized types possible are slices, trait objects, // and extern types, the input safety requirement is currently enough to // satisfy the requirements of align_of_val_raw; this is an implementation - // detail of the language that may not be relied upon outside of std. + // detail of the language that must not be relied upon outside of std. unsafe { data_offset_align(align_of_val_raw(ptr)) } } diff --git a/library/alloc/src/vec/into_iter.rs b/library/alloc/src/vec/into_iter.rs index 8da4d995ba5..0bd152f17a6 100644 --- a/library/alloc/src/vec/into_iter.rs +++ b/library/alloc/src/vec/into_iter.rs @@ -2,7 +2,9 @@ use crate::alloc::{Allocator, Global}; use crate::raw_vec::RawVec; use core::fmt; use core::intrinsics::arith_offset; -use core::iter::{FusedIterator, InPlaceIterable, SourceIter, TrustedLen, TrustedRandomAccess}; +use core::iter::{ + FusedIterator, InPlaceIterable, SourceIter, TrustedLen, TrustedRandomAccessNoCoerce, +}; use core::marker::PhantomData; use core::mem::{self}; use core::ptr::{self, NonNull}; @@ -163,9 +165,10 @@ impl<T, A: Allocator> Iterator for IntoIter<T, A> { self.len() } + #[doc(hidden)] unsafe fn __iterator_get_unchecked(&mut self, i: usize) -> Self::Item where - Self: TrustedRandomAccess, + Self: TrustedRandomAccessNoCoerce, { // SAFETY: the caller must guarantee that `i` is in bounds of the // `Vec<T>`, so `i` cannot overflow an `isize`, and the `self.ptr.add(i)` @@ -218,7 +221,10 @@ unsafe impl<T, A: Allocator> TrustedLen for IntoIter<T, A> {} #[unstable(issue = "none", feature = "std_internals")] // T: Copy as approximation for !Drop since get_unchecked does not advance self.ptr // and thus we can't implement drop-handling -unsafe impl<T, A: Allocator> TrustedRandomAccess for IntoIter<T, A> +// +// TrustedRandomAccess (without NoCoerce) must not be implemented because +// subtypes/supertypes of `T` might not be `Copy` +unsafe impl<T, A: Allocator> TrustedRandomAccessNoCoerce for IntoIter<T, A> where T: Copy, { diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index 4a1d564e2ab..87a0d371815 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -174,12 +174,13 @@ mod spec_extend; /// assert_eq!(vec, [7, 1, 2, 3]); /// ``` /// -/// The [`vec!`] macro is provided to make initialization more convenient: +/// The [`vec!`] macro is provided for convenient initialization: /// /// ``` -/// let mut vec = vec![1, 2, 3]; -/// vec.push(4); -/// assert_eq!(vec, [1, 2, 3, 4]); +/// let mut vec1 = vec![1, 2, 3]; +/// vec1.push(4); +/// let vec2 = Vec::from([1, 2, 3, 4]); +/// assert_eq!(vec1, vec2); /// ``` /// /// It can also initialize each element of a `Vec<T>` with a given value. @@ -459,7 +460,6 @@ impl<T> Vec<T> { /// ``` #[cfg(not(no_global_oom_handling))] #[inline] - #[doc(alias = "malloc")] #[stable(feature = "rust1", since = "1.0.0")] pub fn with_capacity(capacity: usize) -> Self { Self::with_capacity_in(capacity, Global) @@ -799,7 +799,6 @@ impl<T, A: Allocator> Vec<T, A> { /// assert!(vec.capacity() >= 11); /// ``` #[cfg(not(no_global_oom_handling))] - #[doc(alias = "realloc")] #[stable(feature = "rust1", since = "1.0.0")] pub fn reserve(&mut self, additional: usize) { self.buf.reserve(self.len, additional); @@ -812,7 +811,9 @@ impl<T, A: Allocator> Vec<T, A> { /// /// Note that the allocator may give the collection more space than it /// requests. Therefore, capacity can not be relied upon to be precisely - /// minimal. Prefer `reserve` if future insertions are expected. + /// minimal. Prefer [`reserve`] if future insertions are expected. + /// + /// [`reserve`]: Vec::reserve /// /// # Panics /// @@ -826,7 +827,6 @@ impl<T, A: Allocator> Vec<T, A> { /// assert!(vec.capacity() >= 11); /// ``` #[cfg(not(no_global_oom_handling))] - #[doc(alias = "realloc")] #[stable(feature = "rust1", since = "1.0.0")] pub fn reserve_exact(&mut self, additional: usize) { self.buf.reserve_exact(self.len, additional); @@ -864,7 +864,6 @@ impl<T, A: Allocator> Vec<T, A> { /// } /// # process_data(&[1, 2, 3]).expect("why is the test harness OOMing on 12 bytes?"); /// ``` - #[doc(alias = "realloc")] #[unstable(feature = "try_reserve", reason = "new API", issue = "48043")] pub fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError> { self.buf.try_reserve(self.len, additional) @@ -878,7 +877,9 @@ impl<T, A: Allocator> Vec<T, A> { /// /// Note that the allocator may give the collection more space than it /// requests. Therefore, capacity can not be relied upon to be precisely - /// minimal. Prefer `reserve` if future insertions are expected. + /// minimal. Prefer [`reserve`] if future insertions are expected. + /// + /// [`reserve`]: Vec::reserve /// /// # Errors /// @@ -906,7 +907,6 @@ impl<T, A: Allocator> Vec<T, A> { /// } /// # process_data(&[1, 2, 3]).expect("why is the test harness OOMing on 12 bytes?"); /// ``` - #[doc(alias = "realloc")] #[unstable(feature = "try_reserve", reason = "new API", issue = "48043")] pub fn try_reserve_exact(&mut self, additional: usize) -> Result<(), TryReserveError> { self.buf.try_reserve_exact(self.len, additional) @@ -927,7 +927,6 @@ impl<T, A: Allocator> Vec<T, A> { /// assert!(vec.capacity() >= 3); /// ``` #[cfg(not(no_global_oom_handling))] - #[doc(alias = "realloc")] #[stable(feature = "rust1", since = "1.0.0")] pub fn shrink_to_fit(&mut self) { // The capacity is never less than the length, and there's nothing to do when @@ -948,7 +947,6 @@ impl<T, A: Allocator> Vec<T, A> { /// # Examples /// /// ``` - /// #![feature(shrink_to)] /// let mut vec = Vec::with_capacity(10); /// vec.extend([1, 2, 3]); /// assert_eq!(vec.capacity(), 10); @@ -958,8 +956,7 @@ impl<T, A: Allocator> Vec<T, A> { /// assert!(vec.capacity() >= 3); /// ``` #[cfg(not(no_global_oom_handling))] - #[doc(alias = "realloc")] - #[unstable(feature = "shrink_to", reason = "new API", issue = "56431")] + #[stable(feature = "shrink_to", since = "1.56.0")] pub fn shrink_to(&mut self, min_capacity: usize) { if self.capacity() > min_capacity { self.buf.shrink_to_fit(cmp::max(self.len, min_capacity)); @@ -1366,6 +1363,12 @@ impl<T, A: Allocator> Vec<T, A> { /// Removes and returns the element at position `index` within the vector, /// shifting all elements after it to the left. /// + /// Note: Because this shifts over the remaining elements, it has a + /// worst-case performance of O(n). If you don't need the order of elements + /// to be preserved, use [`swap_remove`] instead. + /// + /// [`swap_remove`]: Vec::swap_remove + /// /// # Panics /// /// Panics if `index` is out of bounds. @@ -1378,9 +1381,11 @@ impl<T, A: Allocator> Vec<T, A> { /// assert_eq!(v, [1, 3]); /// ``` #[stable(feature = "rust1", since = "1.0.0")] + #[track_caller] pub fn remove(&mut self, index: usize) -> T { #[cold] #[inline(never)] + #[track_caller] fn assert_failed(index: usize, len: usize) -> ! { panic!("removal index (is {}) should be < len (is {})", index, len); } @@ -1820,7 +1825,6 @@ impl<T, A: Allocator> Vec<T, A> { /// let a = vec![1, 2, 3]; /// assert_eq!(a.len(), 3); /// ``` - #[doc(alias = "length")] #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn len(&self) -> usize { @@ -2236,7 +2240,7 @@ impl<T, A: Allocator> Vec<T, A> { unsafe { let mut ptr = self.as_mut_ptr().add(self.len()); // Use SetLenOnDrop to work around bug where compiler - // may not realize the store through `ptr` through self.set_len() + // might not realize the store through `ptr` through self.set_len() // don't alias. let mut local_len = SetLenOnDrop::new(&mut self.len); @@ -2375,6 +2379,35 @@ impl<T, A: Allocator> ops::DerefMut for Vec<T, A> { } #[cfg(not(no_global_oom_handling))] +trait SpecCloneFrom { + fn clone_from(this: &mut Self, other: &Self); +} + +#[cfg(not(no_global_oom_handling))] +impl<T: Clone, A: Allocator> SpecCloneFrom for Vec<T, A> { + default fn clone_from(this: &mut Self, other: &Self) { + // drop anything that will not be overwritten + this.truncate(other.len()); + + // self.len <= other.len due to the truncate above, so the + // slices here are always in-bounds. + let (init, tail) = other.split_at(this.len()); + + // reuse the contained values' allocations/resources. + this.clone_from_slice(init); + this.extend_from_slice(tail); + } +} + +#[cfg(not(no_global_oom_handling))] +impl<T: Copy, A: Allocator> SpecCloneFrom for Vec<T, A> { + fn clone_from(this: &mut Self, other: &Self) { + this.clear(); + this.extend_from_slice(other); + } +} + +#[cfg(not(no_global_oom_handling))] #[stable(feature = "rust1", since = "1.0.0")] impl<T: Clone, A: Allocator + Clone> Clone for Vec<T, A> { #[cfg(not(test))] @@ -2394,19 +2427,22 @@ impl<T: Clone, A: Allocator + Clone> Clone for Vec<T, A> { } fn clone_from(&mut self, other: &Self) { - // drop anything that will not be overwritten - self.truncate(other.len()); - - // self.len <= other.len due to the truncate above, so the - // slices here are always in-bounds. - let (init, tail) = other.split_at(self.len()); - - // reuse the contained values' allocations/resources. - self.clone_from_slice(init); - self.extend_from_slice(tail); + SpecCloneFrom::clone_from(self, other) } } +/// The hash of a vector is the same as that of the corresponding slice, +/// as required by the `core::borrow::Borrow` implementation. +/// +/// ``` +/// #![feature(build_hasher_simple_hash_one)] +/// use std::hash::BuildHasher; +/// +/// let b = std::collections::hash_map::RandomState::new(); +/// let v: Vec<u8> = vec![0xa8, 0x3c, 0x09]; +/// let s: &[u8] = &[0xa8, 0x3c, 0x09]; +/// assert_eq!(b.hash_one(v), b.hash_one(s)); +/// ``` #[stable(feature = "rust1", since = "1.0.0")] impl<T: Hash, A: Allocator> Hash for Vec<T, A> { #[inline] @@ -2551,6 +2587,8 @@ impl<T, A: Allocator> Vec<T, A> { } unsafe { ptr::write(self.as_mut_ptr().add(len), element); + // Since next() executes user code which can panic we have to bump the length + // after each step. // NB can't overflow since we would have had to alloc the address space self.set_len(len + 1); } @@ -2720,7 +2758,8 @@ unsafe impl<#[may_dangle] T, A: Allocator> Drop for Vec<T, A> { } #[stable(feature = "rust1", since = "1.0.0")] -impl<T> Default for Vec<T> { +#[rustc_const_unstable(feature = "const_default_impls", issue = "87864")] +impl<T> const Default for Vec<T> { /// Creates an empty `Vec<T>`. fn default() -> Vec<T> { Vec::new() diff --git a/library/alloc/src/vec/source_iter_marker.rs b/library/alloc/src/vec/source_iter_marker.rs index e857d284d3a..e05788d99c0 100644 --- a/library/alloc/src/vec/source_iter_marker.rs +++ b/library/alloc/src/vec/source_iter_marker.rs @@ -1,4 +1,4 @@ -use core::iter::{InPlaceIterable, SourceIter, TrustedRandomAccess}; +use core::iter::{InPlaceIterable, SourceIter, TrustedRandomAccessNoCoerce}; use core::mem::{self, ManuallyDrop}; use core::ptr::{self}; @@ -56,7 +56,7 @@ where let src = unsafe { iterator.as_inner().as_into_iter() }; // check if SourceIter contract was upheld - // caveat: if they weren't we may not even make it to this point + // caveat: if they weren't we might not even make it to this point debug_assert_eq!(src_buf, src.buf.as_ptr()); // check InPlaceIterable contract. This is only possible if the iterator advanced the // source pointer at all. If it uses unchecked access via TrustedRandomAccess @@ -71,6 +71,18 @@ where // drop any remaining values at the tail of the source // but prevent drop of the allocation itself once IntoIter goes out of scope // if the drop panics then we also leak any elements collected into dst_buf + // + // FIXME: Since `SpecInPlaceCollect::collect_in_place` above might use + // `__iterator_get_unchecked` internally, this call might be operating on + // a `vec::IntoIter` with incorrect internal state regarding which elements + // have already been “consumed”. However, the `TrustedRandomIteratorNoCoerce` + // implementation of `vec::IntoIter` is only present if the `Vec` elements + // don’t have a destructor, so it doesn’t matter if elements are “dropped multiple times” + // in this case. + // This argument technically currently lacks justification from the `# Safety` docs for + // `SourceIter`/`InPlaceIterable` and/or `TrustedRandomAccess`, so it might be possible that + // someone could inadvertently create new library unsoundness + // involving this `.forget_allocation_drop_remaining()` call. src.forget_allocation_drop_remaining(); let vec = unsafe { Vec::from_raw_parts(dst_buf, len, cap) }; @@ -89,6 +101,8 @@ fn write_in_place_with_drop<T>( // all we can do is check if it's still in range debug_assert!(sink.dst as *const _ <= src_end, "InPlaceIterable contract violation"); ptr::write(sink.dst, item); + // Since this executes user code which can panic we have to bump the pointer + // after each step. sink.dst = sink.dst.add(1); } Ok(sink) @@ -99,6 +113,11 @@ fn write_in_place_with_drop<T>( trait SpecInPlaceCollect<T, I>: Iterator<Item = T> { /// Collects an iterator (`self`) into the destination buffer (`dst`) and returns the number of items /// collected. `end` is the last writable element of the allocation and used for bounds checks. + /// + /// This method is specialized and one of its implementations makes use of + /// `Iterator::__iterator_get_unchecked` calls with a `TrustedRandomAccessNoCoerce` bound + /// on `I` which means the caller of this method must take the safety conditions + /// of that trait into consideration. fn collect_in_place(&mut self, dst: *mut T, end: *const T) -> usize; } @@ -122,7 +141,7 @@ where impl<T, I> SpecInPlaceCollect<T, I> for I where - I: Iterator<Item = T> + TrustedRandomAccess, + I: Iterator<Item = T> + TrustedRandomAccessNoCoerce, { #[inline] fn collect_in_place(&mut self, dst_buf: *mut T, end: *const T) -> usize { @@ -136,6 +155,8 @@ where let dst = dst_buf.offset(i as isize); debug_assert!(dst as *const _ <= end, "InPlaceIterable contract violation"); ptr::write(dst, self.__iterator_get_unchecked(i)); + // Since this executes user code which can panic we have to bump the pointer + // after each step. drop_guard.dst = dst.add(1); } } diff --git a/library/alloc/src/vec/spec_extend.rs b/library/alloc/src/vec/spec_extend.rs index c6f4f22a01f..c3b4534096d 100644 --- a/library/alloc/src/vec/spec_extend.rs +++ b/library/alloc/src/vec/spec_extend.rs @@ -40,6 +40,8 @@ where iterator.for_each(move |element| { ptr::write(ptr, element); ptr = ptr.offset(1); + // Since the loop executes user code which can panic we have to bump the pointer + // after each step. // NB can't overflow since we would have had to alloc the address space local_len.increment_len(1); }); diff --git a/library/alloc/tests/binary_heap.rs b/library/alloc/tests/binary_heap.rs index a7913dcd287..f32118bb563 100644 --- a/library/alloc/tests/binary_heap.rs +++ b/library/alloc/tests/binary_heap.rs @@ -408,7 +408,7 @@ fn test_retain() { // old binaryheap failed this test // // Integrity means that all elements are present after a comparison panics, -// even if the order may not be correct. +// even if the order might not be correct. // // Destructors must be called exactly once per element. // FIXME: re-enable emscripten once it can unwind again diff --git a/library/alloc/tests/const_fns.rs b/library/alloc/tests/const_fns.rs new file mode 100644 index 00000000000..da58ae92e11 --- /dev/null +++ b/library/alloc/tests/const_fns.rs @@ -0,0 +1,53 @@ +// Test const functions in the library + +use core::cmp::Ordering; + +// FIXME remove this struct once we put `K: ?const Ord` on BTreeMap::new. +#[derive(PartialEq, Eq, PartialOrd)] +pub struct MyType; + +impl const Ord for MyType { + fn cmp(&self, _: &Self) -> Ordering { + Ordering::Equal + } + + fn max(self, _: Self) -> Self { + Self + } + + fn min(self, _: Self) -> Self { + Self + } + + fn clamp(self, _: Self, _: Self) -> Self { + Self + } +} + +pub const MY_VEC: Vec<usize> = Vec::new(); +pub const MY_VEC2: Vec<usize> = Default::default(); + +pub const MY_STRING: String = String::new(); +pub const MY_STRING2: String = Default::default(); + +use std::collections::{BTreeMap, BTreeSet}; + +pub const MY_BTREEMAP: BTreeMap<MyType, MyType> = BTreeMap::new(); +pub const MAP: &'static BTreeMap<MyType, MyType> = &MY_BTREEMAP; +pub const MAP_LEN: usize = MAP.len(); +pub const MAP_IS_EMPTY: bool = MAP.is_empty(); + +pub const MY_BTREESET: BTreeSet<MyType> = BTreeSet::new(); +pub const SET: &'static BTreeSet<MyType> = &MY_BTREESET; +pub const SET_LEN: usize = SET.len(); +pub const SET_IS_EMPTY: bool = SET.is_empty(); + +#[test] +fn test_const() { + assert_eq!(MY_VEC, MY_VEC2); + assert_eq!(MY_STRING, MY_STRING2); + + assert_eq!(MAP_LEN, 0); + assert_eq!(SET_LEN, 0); + assert!(MAP_IS_EMPTY && SET_IS_EMPTY); +} diff --git a/library/alloc/tests/lib.rs b/library/alloc/tests/lib.rs index 3143afa269d..5767108d423 100644 --- a/library/alloc/tests/lib.rs +++ b/library/alloc/tests/lib.rs @@ -1,4 +1,5 @@ #![feature(allocator_api)] +#![feature(assert_matches)] #![feature(box_syntax)] #![feature(cow_is_borrowed)] #![feature(const_cow_is_borrowed)] @@ -8,6 +9,7 @@ #![feature(pattern)] #![feature(trusted_len)] #![feature(try_reserve)] +#![feature(try_reserve_kind)] #![feature(unboxed_closures)] #![feature(associated_type_bounds)] #![feature(binary_heap_into_iter_sorted)] @@ -21,6 +23,9 @@ #![feature(slice_partition_dedup)] #![feature(vec_spare_capacity)] #![feature(string_remove_matches)] +#![feature(const_btree_new)] +#![feature(const_default_impls)] +#![feature(const_trait_impl)] use std::collections::hash_map::DefaultHasher; use std::hash::{Hash, Hasher}; @@ -30,6 +35,7 @@ mod binary_heap; mod borrow; mod boxed; mod btree_set_hash; +mod const_fns; mod cow_str; mod fmt; mod heap; diff --git a/library/alloc/tests/slice.rs b/library/alloc/tests/slice.rs index 1fb4a51acfd..13b8c059e37 100644 --- a/library/alloc/tests/slice.rs +++ b/library/alloc/tests/slice.rs @@ -1,6 +1,7 @@ use std::cell::Cell; use std::cmp::Ordering::{self, Equal, Greater, Less}; use std::convert::identity; +use std::fmt; use std::mem; use std::panic; use std::rc::Rc; @@ -994,6 +995,66 @@ fn test_rsplitnator() { } #[test] +fn test_split_iterators_size_hint() { + #[derive(Copy, Clone)] + enum Bounds { + Lower, + Upper, + } + fn assert_tight_size_hints(mut it: impl Iterator, which: Bounds, ctx: impl fmt::Display) { + match which { + Bounds::Lower => { + let mut lower_bounds = vec![it.size_hint().0]; + while let Some(_) = it.next() { + lower_bounds.push(it.size_hint().0); + } + let target: Vec<_> = (0..lower_bounds.len()).rev().collect(); + assert_eq!(lower_bounds, target, "lower bounds incorrect or not tight: {}", ctx); + } + Bounds::Upper => { + let mut upper_bounds = vec![it.size_hint().1]; + while let Some(_) = it.next() { + upper_bounds.push(it.size_hint().1); + } + let target: Vec<_> = (0..upper_bounds.len()).map(Some).rev().collect(); + assert_eq!(upper_bounds, target, "upper bounds incorrect or not tight: {}", ctx); + } + } + } + + for len in 0..=2 { + let mut v: Vec<u8> = (0..len).collect(); + + // p: predicate, b: bound selection + for (p, b) in [ + // with a predicate always returning false, the split*-iterators + // become maximally short, so the size_hint lower bounds are tight + ((|_| false) as fn(&_) -> _, Bounds::Lower), + // with a predicate always returning true, the split*-iterators + // become maximally long, so the size_hint upper bounds are tight + ((|_| true) as fn(&_) -> _, Bounds::Upper), + ] { + use assert_tight_size_hints as a; + use format_args as f; + + a(v.split(p), b, "split"); + a(v.split_mut(p), b, "split_mut"); + a(v.split_inclusive(p), b, "split_inclusive"); + a(v.split_inclusive_mut(p), b, "split_inclusive_mut"); + a(v.rsplit(p), b, "rsplit"); + a(v.rsplit_mut(p), b, "rsplit_mut"); + + for n in 0..=3 { + a(v.splitn(n, p), b, f!("splitn, n = {}", n)); + a(v.splitn_mut(n, p), b, f!("splitn_mut, n = {}", n)); + a(v.rsplitn(n, p), b, f!("rsplitn, n = {}", n)); + a(v.rsplitn_mut(n, p), b, f!("rsplitn_mut, n = {}", n)); + } + } + } +} + +#[test] fn test_windowsator() { let v = &[1, 2, 3, 4]; diff --git a/library/alloc/tests/str.rs b/library/alloc/tests/str.rs index 6df8d8c2f35..d3a87c056cf 100644 --- a/library/alloc/tests/str.rs +++ b/library/alloc/tests/str.rs @@ -534,7 +534,7 @@ mod slice_index { #[test] #[should_panic] fn test_slice_fail() { - &"中华Việt Nam"[0..2]; + let _ = &"中华Việt Nam"[0..2]; } panic_cases! { @@ -714,13 +714,13 @@ mod slice_index { #[test] #[should_panic(expected = "byte index 1024 is out of bounds of `Lorem ipsum dolor sit amet")] fn test_slice_fail_truncated_1() { - &LOREM_PARAGRAPH[..1024]; + let _ = &LOREM_PARAGRAPH[..1024]; } // check the truncation in the panic message #[test] #[should_panic(expected = "luctus, im`[...]")] fn test_slice_fail_truncated_2() { - &LOREM_PARAGRAPH[..1024]; + let _ = &LOREM_PARAGRAPH[..1024]; } } @@ -735,7 +735,7 @@ fn test_str_slice_rangetoinclusive_ok() { #[should_panic] fn test_str_slice_rangetoinclusive_notok() { let s = "abcαβγ"; - &s[..=3]; + let _ = &s[..=3]; } #[test] @@ -751,7 +751,7 @@ fn test_str_slicemut_rangetoinclusive_ok() { fn test_str_slicemut_rangetoinclusive_notok() { let mut s = "abcαβγ".to_owned(); let s: &mut str = &mut s; - &mut s[..=3]; + let _ = &mut s[..=3]; } #[test] @@ -1873,6 +1873,47 @@ mod pattern { "* \t", [Reject(0, 1), Reject(1, 2), Reject(2, 3),] ); + + // See #85462 + #[test] + fn str_searcher_empty_needle_after_done() { + // Empty needle and haystack + { + let mut searcher = "".into_searcher(""); + + assert_eq!(searcher.next(), SearchStep::Match(0, 0)); + assert_eq!(searcher.next(), SearchStep::Done); + assert_eq!(searcher.next(), SearchStep::Done); + assert_eq!(searcher.next(), SearchStep::Done); + + let mut searcher = "".into_searcher(""); + + assert_eq!(searcher.next_back(), SearchStep::Match(0, 0)); + assert_eq!(searcher.next_back(), SearchStep::Done); + assert_eq!(searcher.next_back(), SearchStep::Done); + assert_eq!(searcher.next_back(), SearchStep::Done); + } + // Empty needle and non-empty haystack + { + let mut searcher = "".into_searcher("a"); + + assert_eq!(searcher.next(), SearchStep::Match(0, 0)); + assert_eq!(searcher.next(), SearchStep::Reject(0, 1)); + assert_eq!(searcher.next(), SearchStep::Match(1, 1)); + assert_eq!(searcher.next(), SearchStep::Done); + assert_eq!(searcher.next(), SearchStep::Done); + assert_eq!(searcher.next(), SearchStep::Done); + + let mut searcher = "".into_searcher("a"); + + assert_eq!(searcher.next_back(), SearchStep::Match(1, 1)); + assert_eq!(searcher.next_back(), SearchStep::Reject(0, 1)); + assert_eq!(searcher.next_back(), SearchStep::Match(0, 0)); + assert_eq!(searcher.next_back(), SearchStep::Done); + assert_eq!(searcher.next_back(), SearchStep::Done); + assert_eq!(searcher.next_back(), SearchStep::Done); + } + } } macro_rules! generate_iterator_test { diff --git a/library/alloc/tests/string.rs b/library/alloc/tests/string.rs index 9ec0ee97ab9..7be137131ff 100644 --- a/library/alloc/tests/string.rs +++ b/library/alloc/tests/string.rs @@ -1,6 +1,7 @@ +use std::assert_matches::assert_matches; use std::borrow::Cow; use std::cell::Cell; -use std::collections::TryReserveError::*; +use std::collections::TryReserveErrorKind::*; use std::ops::Bound; use std::ops::Bound::*; use std::ops::RangeBounds; @@ -703,38 +704,42 @@ fn test_try_reserve() { let mut empty_string: String = String::new(); // Check isize::MAX doesn't count as an overflow - if let Err(CapacityOverflow) = empty_string.try_reserve(MAX_CAP) { + if let Err(CapacityOverflow) = empty_string.try_reserve(MAX_CAP).map_err(|e| e.kind()) { panic!("isize::MAX shouldn't trigger an overflow!"); } // Play it again, frank! (just to be sure) - if let Err(CapacityOverflow) = empty_string.try_reserve(MAX_CAP) { + if let Err(CapacityOverflow) = empty_string.try_reserve(MAX_CAP).map_err(|e| e.kind()) { panic!("isize::MAX shouldn't trigger an overflow!"); } if guards_against_isize { // Check isize::MAX + 1 does count as overflow - if let Err(CapacityOverflow) = empty_string.try_reserve(MAX_CAP + 1) { - } else { - panic!("isize::MAX + 1 should trigger an overflow!") - } + assert_matches!( + empty_string.try_reserve(MAX_CAP + 1).map_err(|e| e.kind()), + Err(CapacityOverflow), + "isize::MAX + 1 should trigger an overflow!" + ); // Check usize::MAX does count as overflow - if let Err(CapacityOverflow) = empty_string.try_reserve(MAX_USIZE) { - } else { - panic!("usize::MAX should trigger an overflow!") - } + assert_matches!( + empty_string.try_reserve(MAX_USIZE).map_err(|e| e.kind()), + Err(CapacityOverflow), + "usize::MAX should trigger an overflow!" + ); } else { // Check isize::MAX + 1 is an OOM - if let Err(AllocError { .. }) = empty_string.try_reserve(MAX_CAP + 1) { - } else { - panic!("isize::MAX + 1 should trigger an OOM!") - } + assert_matches!( + empty_string.try_reserve(MAX_CAP + 1).map_err(|e| e.kind()), + Err(AllocError { .. }), + "isize::MAX + 1 should trigger an OOM!" + ); // Check usize::MAX is an OOM - if let Err(AllocError { .. }) = empty_string.try_reserve(MAX_USIZE) { - } else { - panic!("usize::MAX should trigger an OOM!") - } + assert_matches!( + empty_string.try_reserve(MAX_USIZE).map_err(|e| e.kind()), + Err(AllocError { .. }), + "usize::MAX should trigger an OOM!" + ); } } @@ -742,28 +747,31 @@ fn test_try_reserve() { // Same basic idea, but with non-zero len let mut ten_bytes: String = String::from("0123456789"); - if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_CAP - 10) { + if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_CAP - 10).map_err(|e| e.kind()) { panic!("isize::MAX shouldn't trigger an overflow!"); } - if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_CAP - 10) { + if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_CAP - 10).map_err(|e| e.kind()) { panic!("isize::MAX shouldn't trigger an overflow!"); } if guards_against_isize { - if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_CAP - 9) { - } else { - panic!("isize::MAX + 1 should trigger an overflow!"); - } + assert_matches!( + ten_bytes.try_reserve(MAX_CAP - 9).map_err(|e| e.kind()), + Err(CapacityOverflow), + "isize::MAX + 1 should trigger an overflow!" + ); } else { - if let Err(AllocError { .. }) = ten_bytes.try_reserve(MAX_CAP - 9) { - } else { - panic!("isize::MAX + 1 should trigger an OOM!") - } + assert_matches!( + ten_bytes.try_reserve(MAX_CAP - 9).map_err(|e| e.kind()), + Err(AllocError { .. }), + "isize::MAX + 1 should trigger an OOM!" + ); } // Should always overflow in the add-to-len - if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_USIZE) { - } else { - panic!("usize::MAX should trigger an overflow!") - } + assert_matches!( + ten_bytes.try_reserve(MAX_USIZE).map_err(|e| e.kind()), + Err(CapacityOverflow), + "usize::MAX should trigger an overflow!" + ); } } @@ -782,60 +790,73 @@ fn test_try_reserve_exact() { { let mut empty_string: String = String::new(); - if let Err(CapacityOverflow) = empty_string.try_reserve_exact(MAX_CAP) { + if let Err(CapacityOverflow) = empty_string.try_reserve_exact(MAX_CAP).map_err(|e| e.kind()) + { panic!("isize::MAX shouldn't trigger an overflow!"); } - if let Err(CapacityOverflow) = empty_string.try_reserve_exact(MAX_CAP) { + if let Err(CapacityOverflow) = empty_string.try_reserve_exact(MAX_CAP).map_err(|e| e.kind()) + { panic!("isize::MAX shouldn't trigger an overflow!"); } if guards_against_isize { - if let Err(CapacityOverflow) = empty_string.try_reserve_exact(MAX_CAP + 1) { - } else { - panic!("isize::MAX + 1 should trigger an overflow!") - } - - if let Err(CapacityOverflow) = empty_string.try_reserve_exact(MAX_USIZE) { - } else { - panic!("usize::MAX should trigger an overflow!") - } + assert_matches!( + empty_string.try_reserve_exact(MAX_CAP + 1).map_err(|e| e.kind()), + Err(CapacityOverflow), + "isize::MAX + 1 should trigger an overflow!" + ); + + assert_matches!( + empty_string.try_reserve_exact(MAX_USIZE).map_err(|e| e.kind()), + Err(CapacityOverflow), + "usize::MAX should trigger an overflow!" + ); } else { - if let Err(AllocError { .. }) = empty_string.try_reserve_exact(MAX_CAP + 1) { - } else { - panic!("isize::MAX + 1 should trigger an OOM!") - } - - if let Err(AllocError { .. }) = empty_string.try_reserve_exact(MAX_USIZE) { - } else { - panic!("usize::MAX should trigger an OOM!") - } + assert_matches!( + empty_string.try_reserve_exact(MAX_CAP + 1).map_err(|e| e.kind()), + Err(AllocError { .. }), + "isize::MAX + 1 should trigger an OOM!" + ); + + assert_matches!( + empty_string.try_reserve_exact(MAX_USIZE).map_err(|e| e.kind()), + Err(AllocError { .. }), + "usize::MAX should trigger an OOM!" + ); } } { let mut ten_bytes: String = String::from("0123456789"); - if let Err(CapacityOverflow) = ten_bytes.try_reserve_exact(MAX_CAP - 10) { + if let Err(CapacityOverflow) = + ten_bytes.try_reserve_exact(MAX_CAP - 10).map_err(|e| e.kind()) + { panic!("isize::MAX shouldn't trigger an overflow!"); } - if let Err(CapacityOverflow) = ten_bytes.try_reserve_exact(MAX_CAP - 10) { + if let Err(CapacityOverflow) = + ten_bytes.try_reserve_exact(MAX_CAP - 10).map_err(|e| e.kind()) + { panic!("isize::MAX shouldn't trigger an overflow!"); } if guards_against_isize { - if let Err(CapacityOverflow) = ten_bytes.try_reserve_exact(MAX_CAP - 9) { - } else { - panic!("isize::MAX + 1 should trigger an overflow!"); - } - } else { - if let Err(AllocError { .. }) = ten_bytes.try_reserve_exact(MAX_CAP - 9) { - } else { - panic!("isize::MAX + 1 should trigger an OOM!") - } - } - if let Err(CapacityOverflow) = ten_bytes.try_reserve_exact(MAX_USIZE) { + assert_matches!( + ten_bytes.try_reserve_exact(MAX_CAP - 9).map_err(|e| e.kind()), + Err(CapacityOverflow), + "isize::MAX + 1 should trigger an overflow!" + ); } else { - panic!("usize::MAX should trigger an overflow!") + assert_matches!( + ten_bytes.try_reserve_exact(MAX_CAP - 9).map_err(|e| e.kind()), + Err(AllocError { .. }), + "isize::MAX + 1 should trigger an OOM!" + ); } + assert_matches!( + ten_bytes.try_reserve_exact(MAX_USIZE).map_err(|e| e.kind()), + Err(CapacityOverflow), + "usize::MAX should trigger an overflow!" + ); } } diff --git a/library/alloc/tests/vec.rs b/library/alloc/tests/vec.rs index c203cdafecb..c2df50b48f5 100644 --- a/library/alloc/tests/vec.rs +++ b/library/alloc/tests/vec.rs @@ -1,6 +1,7 @@ +use std::assert_matches::assert_matches; use std::borrow::Cow; use std::cell::Cell; -use std::collections::TryReserveError::*; +use std::collections::TryReserveErrorKind::*; use std::fmt::Debug; use std::iter::InPlaceIterable; use std::mem::{size_of, swap}; @@ -542,35 +543,35 @@ fn test_index_out_of_bounds() { #[should_panic] fn test_slice_out_of_bounds_1() { let x = vec![1, 2, 3, 4, 5]; - &x[!0..]; + let _ = &x[!0..]; } #[test] #[should_panic] fn test_slice_out_of_bounds_2() { let x = vec![1, 2, 3, 4, 5]; - &x[..6]; + let _ = &x[..6]; } #[test] #[should_panic] fn test_slice_out_of_bounds_3() { let x = vec![1, 2, 3, 4, 5]; - &x[!0..4]; + let _ = &x[!0..4]; } #[test] #[should_panic] fn test_slice_out_of_bounds_4() { let x = vec![1, 2, 3, 4, 5]; - &x[1..6]; + let _ = &x[1..6]; } #[test] #[should_panic] fn test_slice_out_of_bounds_5() { let x = vec![1, 2, 3, 4, 5]; - &x[3..2]; + let _ = &x[3..2]; } #[test] @@ -1478,38 +1479,42 @@ fn test_try_reserve() { let mut empty_bytes: Vec<u8> = Vec::new(); // Check isize::MAX doesn't count as an overflow - if let Err(CapacityOverflow) = empty_bytes.try_reserve(MAX_CAP) { + if let Err(CapacityOverflow) = empty_bytes.try_reserve(MAX_CAP).map_err(|e| e.kind()) { panic!("isize::MAX shouldn't trigger an overflow!"); } // Play it again, frank! (just to be sure) - if let Err(CapacityOverflow) = empty_bytes.try_reserve(MAX_CAP) { + if let Err(CapacityOverflow) = empty_bytes.try_reserve(MAX_CAP).map_err(|e| e.kind()) { panic!("isize::MAX shouldn't trigger an overflow!"); } if guards_against_isize { // Check isize::MAX + 1 does count as overflow - if let Err(CapacityOverflow) = empty_bytes.try_reserve(MAX_CAP + 1) { - } else { - panic!("isize::MAX + 1 should trigger an overflow!") - } + assert_matches!( + empty_bytes.try_reserve(MAX_CAP + 1).map_err(|e| e.kind()), + Err(CapacityOverflow), + "isize::MAX + 1 should trigger an overflow!" + ); // Check usize::MAX does count as overflow - if let Err(CapacityOverflow) = empty_bytes.try_reserve(MAX_USIZE) { - } else { - panic!("usize::MAX should trigger an overflow!") - } + assert_matches!( + empty_bytes.try_reserve(MAX_USIZE).map_err(|e| e.kind()), + Err(CapacityOverflow), + "usize::MAX should trigger an overflow!" + ); } else { // Check isize::MAX + 1 is an OOM - if let Err(AllocError { .. }) = empty_bytes.try_reserve(MAX_CAP + 1) { - } else { - panic!("isize::MAX + 1 should trigger an OOM!") - } + assert_matches!( + empty_bytes.try_reserve(MAX_CAP + 1).map_err(|e| e.kind()), + Err(AllocError { .. }), + "isize::MAX + 1 should trigger an OOM!" + ); // Check usize::MAX is an OOM - if let Err(AllocError { .. }) = empty_bytes.try_reserve(MAX_USIZE) { - } else { - panic!("usize::MAX should trigger an OOM!") - } + assert_matches!( + empty_bytes.try_reserve(MAX_USIZE).map_err(|e| e.kind()), + Err(AllocError { .. }), + "usize::MAX should trigger an OOM!" + ); } } @@ -1517,56 +1522,64 @@ fn test_try_reserve() { // Same basic idea, but with non-zero len let mut ten_bytes: Vec<u8> = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; - if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_CAP - 10) { + if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_CAP - 10).map_err(|e| e.kind()) { panic!("isize::MAX shouldn't trigger an overflow!"); } - if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_CAP - 10) { + if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_CAP - 10).map_err(|e| e.kind()) { panic!("isize::MAX shouldn't trigger an overflow!"); } if guards_against_isize { - if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_CAP - 9) { - } else { - panic!("isize::MAX + 1 should trigger an overflow!"); - } + assert_matches!( + ten_bytes.try_reserve(MAX_CAP - 9).map_err(|e| e.kind()), + Err(CapacityOverflow), + "isize::MAX + 1 should trigger an overflow!" + ); } else { - if let Err(AllocError { .. }) = ten_bytes.try_reserve(MAX_CAP - 9) { - } else { - panic!("isize::MAX + 1 should trigger an OOM!") - } + assert_matches!( + ten_bytes.try_reserve(MAX_CAP - 9).map_err(|e| e.kind()), + Err(AllocError { .. }), + "isize::MAX + 1 should trigger an OOM!" + ); } // Should always overflow in the add-to-len - if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_USIZE) { - } else { - panic!("usize::MAX should trigger an overflow!") - } + assert_matches!( + ten_bytes.try_reserve(MAX_USIZE).map_err(|e| e.kind()), + Err(CapacityOverflow), + "usize::MAX should trigger an overflow!" + ); } { // Same basic idea, but with interesting type size let mut ten_u32s: Vec<u32> = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; - if let Err(CapacityOverflow) = ten_u32s.try_reserve(MAX_CAP / 4 - 10) { + if let Err(CapacityOverflow) = ten_u32s.try_reserve(MAX_CAP / 4 - 10).map_err(|e| e.kind()) + { panic!("isize::MAX shouldn't trigger an overflow!"); } - if let Err(CapacityOverflow) = ten_u32s.try_reserve(MAX_CAP / 4 - 10) { + if let Err(CapacityOverflow) = ten_u32s.try_reserve(MAX_CAP / 4 - 10).map_err(|e| e.kind()) + { panic!("isize::MAX shouldn't trigger an overflow!"); } if guards_against_isize { - if let Err(CapacityOverflow) = ten_u32s.try_reserve(MAX_CAP / 4 - 9) { - } else { - panic!("isize::MAX + 1 should trigger an overflow!"); - } + assert_matches!( + ten_u32s.try_reserve(MAX_CAP / 4 - 9).map_err(|e| e.kind()), + Err(CapacityOverflow), + "isize::MAX + 1 should trigger an overflow!" + ); } else { - if let Err(AllocError { .. }) = ten_u32s.try_reserve(MAX_CAP / 4 - 9) { - } else { - panic!("isize::MAX + 1 should trigger an OOM!") - } + assert_matches!( + ten_u32s.try_reserve(MAX_CAP / 4 - 9).map_err(|e| e.kind()), + Err(AllocError { .. }), + "isize::MAX + 1 should trigger an OOM!" + ); } // Should fail in the mul-by-size - if let Err(CapacityOverflow) = ten_u32s.try_reserve(MAX_USIZE - 20) { - } else { - panic!("usize::MAX should trigger an overflow!"); - } + assert_matches!( + ten_u32s.try_reserve(MAX_USIZE - 20).map_err(|e| e.kind()), + Err(CapacityOverflow), + "usize::MAX should trigger an overflow!" + ); } } @@ -1585,86 +1598,106 @@ fn test_try_reserve_exact() { { let mut empty_bytes: Vec<u8> = Vec::new(); - if let Err(CapacityOverflow) = empty_bytes.try_reserve_exact(MAX_CAP) { + if let Err(CapacityOverflow) = empty_bytes.try_reserve_exact(MAX_CAP).map_err(|e| e.kind()) + { panic!("isize::MAX shouldn't trigger an overflow!"); } - if let Err(CapacityOverflow) = empty_bytes.try_reserve_exact(MAX_CAP) { + if let Err(CapacityOverflow) = empty_bytes.try_reserve_exact(MAX_CAP).map_err(|e| e.kind()) + { panic!("isize::MAX shouldn't trigger an overflow!"); } if guards_against_isize { - if let Err(CapacityOverflow) = empty_bytes.try_reserve_exact(MAX_CAP + 1) { - } else { - panic!("isize::MAX + 1 should trigger an overflow!") - } - - if let Err(CapacityOverflow) = empty_bytes.try_reserve_exact(MAX_USIZE) { - } else { - panic!("usize::MAX should trigger an overflow!") - } + assert_matches!( + empty_bytes.try_reserve_exact(MAX_CAP + 1).map_err(|e| e.kind()), + Err(CapacityOverflow), + "isize::MAX + 1 should trigger an overflow!" + ); + + assert_matches!( + empty_bytes.try_reserve_exact(MAX_USIZE).map_err(|e| e.kind()), + Err(CapacityOverflow), + "usize::MAX should trigger an overflow!" + ); } else { - if let Err(AllocError { .. }) = empty_bytes.try_reserve_exact(MAX_CAP + 1) { - } else { - panic!("isize::MAX + 1 should trigger an OOM!") - } + assert_matches!( + empty_bytes.try_reserve_exact(MAX_CAP + 1).map_err(|e| e.kind()), + Err(AllocError { .. }), + "isize::MAX + 1 should trigger an OOM!" + ); - if let Err(AllocError { .. }) = empty_bytes.try_reserve_exact(MAX_USIZE) { - } else { - panic!("usize::MAX should trigger an OOM!") - } + assert_matches!( + empty_bytes.try_reserve_exact(MAX_USIZE).map_err(|e| e.kind()), + Err(AllocError { .. }), + "usize::MAX should trigger an OOM!" + ); } } { let mut ten_bytes: Vec<u8> = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; - if let Err(CapacityOverflow) = ten_bytes.try_reserve_exact(MAX_CAP - 10) { + if let Err(CapacityOverflow) = + ten_bytes.try_reserve_exact(MAX_CAP - 10).map_err(|e| e.kind()) + { panic!("isize::MAX shouldn't trigger an overflow!"); } - if let Err(CapacityOverflow) = ten_bytes.try_reserve_exact(MAX_CAP - 10) { + if let Err(CapacityOverflow) = + ten_bytes.try_reserve_exact(MAX_CAP - 10).map_err(|e| e.kind()) + { panic!("isize::MAX shouldn't trigger an overflow!"); } if guards_against_isize { - if let Err(CapacityOverflow) = ten_bytes.try_reserve_exact(MAX_CAP - 9) { - } else { - panic!("isize::MAX + 1 should trigger an overflow!"); - } + assert_matches!( + ten_bytes.try_reserve_exact(MAX_CAP - 9).map_err(|e| e.kind()), + Err(CapacityOverflow), + "isize::MAX + 1 should trigger an overflow!" + ); } else { - if let Err(AllocError { .. }) = ten_bytes.try_reserve_exact(MAX_CAP - 9) { - } else { - panic!("isize::MAX + 1 should trigger an OOM!") - } - } - if let Err(CapacityOverflow) = ten_bytes.try_reserve_exact(MAX_USIZE) { - } else { - panic!("usize::MAX should trigger an overflow!") + assert_matches!( + ten_bytes.try_reserve_exact(MAX_CAP - 9).map_err(|e| e.kind()), + Err(AllocError { .. }), + "isize::MAX + 1 should trigger an OOM!" + ); } + assert_matches!( + ten_bytes.try_reserve_exact(MAX_USIZE).map_err(|e| e.kind()), + Err(CapacityOverflow), + "usize::MAX should trigger an overflow!" + ); } { let mut ten_u32s: Vec<u32> = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; - if let Err(CapacityOverflow) = ten_u32s.try_reserve_exact(MAX_CAP / 4 - 10) { + if let Err(CapacityOverflow) = + ten_u32s.try_reserve_exact(MAX_CAP / 4 - 10).map_err(|e| e.kind()) + { panic!("isize::MAX shouldn't trigger an overflow!"); } - if let Err(CapacityOverflow) = ten_u32s.try_reserve_exact(MAX_CAP / 4 - 10) { + if let Err(CapacityOverflow) = + ten_u32s.try_reserve_exact(MAX_CAP / 4 - 10).map_err(|e| e.kind()) + { panic!("isize::MAX shouldn't trigger an overflow!"); } if guards_against_isize { - if let Err(CapacityOverflow) = ten_u32s.try_reserve_exact(MAX_CAP / 4 - 9) { - } else { - panic!("isize::MAX + 1 should trigger an overflow!"); - } + assert_matches!( + ten_u32s.try_reserve_exact(MAX_CAP / 4 - 9).map_err(|e| e.kind()), + Err(CapacityOverflow), + "isize::MAX + 1 should trigger an overflow!" + ); } else { - if let Err(AllocError { .. }) = ten_u32s.try_reserve_exact(MAX_CAP / 4 - 9) { - } else { - panic!("isize::MAX + 1 should trigger an OOM!") - } - } - if let Err(CapacityOverflow) = ten_u32s.try_reserve_exact(MAX_USIZE - 20) { - } else { - panic!("usize::MAX should trigger an overflow!") - } + assert_matches!( + ten_u32s.try_reserve_exact(MAX_CAP / 4 - 9).map_err(|e| e.kind()), + Err(AllocError { .. }), + "isize::MAX + 1 should trigger an OOM!" + ); + } + assert_matches!( + ten_u32s.try_reserve_exact(MAX_USIZE - 20).map_err(|e| e.kind()), + Err(CapacityOverflow), + "usize::MAX should trigger an overflow!" + ); } } diff --git a/library/alloc/tests/vec_deque.rs b/library/alloc/tests/vec_deque.rs index d7140cf9759..ddfb4c00c26 100644 --- a/library/alloc/tests/vec_deque.rs +++ b/library/alloc/tests/vec_deque.rs @@ -1,4 +1,5 @@ -use std::collections::TryReserveError::*; +use std::assert_matches::assert_matches; +use std::collections::TryReserveErrorKind::*; use std::collections::{vec_deque::Drain, VecDeque}; use std::fmt::Debug; use std::mem::size_of; @@ -1171,35 +1172,38 @@ fn test_try_reserve() { let mut empty_bytes: VecDeque<u8> = VecDeque::new(); // Check isize::MAX doesn't count as an overflow - if let Err(CapacityOverflow) = empty_bytes.try_reserve(MAX_CAP) { + if let Err(CapacityOverflow) = empty_bytes.try_reserve(MAX_CAP).map_err(|e| e.kind()) { panic!("isize::MAX shouldn't trigger an overflow!"); } // Play it again, frank! (just to be sure) - if let Err(CapacityOverflow) = empty_bytes.try_reserve(MAX_CAP) { + if let Err(CapacityOverflow) = empty_bytes.try_reserve(MAX_CAP).map_err(|e| e.kind()) { panic!("isize::MAX shouldn't trigger an overflow!"); } if guards_against_isize { // Check isize::MAX + 1 does count as overflow - if let Err(CapacityOverflow) = empty_bytes.try_reserve(MAX_CAP + 1) { - } else { - panic!("isize::MAX + 1 should trigger an overflow!") - } + assert_matches!( + empty_bytes.try_reserve(MAX_CAP + 1).map_err(|e| e.kind()), + Err(CapacityOverflow), + "isize::MAX + 1 should trigger an overflow!" + ); // Check usize::MAX does count as overflow - if let Err(CapacityOverflow) = empty_bytes.try_reserve(MAX_USIZE) { - } else { - panic!("usize::MAX should trigger an overflow!") - } + assert_matches!( + empty_bytes.try_reserve(MAX_USIZE).map_err(|e| e.kind()), + Err(CapacityOverflow), + "usize::MAX should trigger an overflow!" + ); } else { // Check isize::MAX is an OOM // VecDeque starts with capacity 7, always adds 1 to the capacity // and also rounds the number to next power of 2 so this is the // furthest we can go without triggering CapacityOverflow - if let Err(AllocError { .. }) = empty_bytes.try_reserve(MAX_CAP) { - } else { - panic!("isize::MAX + 1 should trigger an OOM!") - } + assert_matches!( + empty_bytes.try_reserve(MAX_CAP).map_err(|e| e.kind()), + Err(AllocError { .. }), + "isize::MAX + 1 should trigger an OOM!" + ); } } @@ -1207,56 +1211,64 @@ fn test_try_reserve() { // Same basic idea, but with non-zero len let mut ten_bytes: VecDeque<u8> = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10].into_iter().collect(); - if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_CAP - 10) { + if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_CAP - 10).map_err(|e| e.kind()) { panic!("isize::MAX shouldn't trigger an overflow!"); } - if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_CAP - 10) { + if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_CAP - 10).map_err(|e| e.kind()) { panic!("isize::MAX shouldn't trigger an overflow!"); } if guards_against_isize { - if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_CAP - 9) { - } else { - panic!("isize::MAX + 1 should trigger an overflow!"); - } + assert_matches!( + ten_bytes.try_reserve(MAX_CAP - 9).map_err(|e| e.kind()), + Err(CapacityOverflow), + "isize::MAX + 1 should trigger an overflow!" + ); } else { - if let Err(AllocError { .. }) = ten_bytes.try_reserve(MAX_CAP - 9) { - } else { - panic!("isize::MAX + 1 should trigger an OOM!") - } + assert_matches!( + ten_bytes.try_reserve(MAX_CAP - 9).map_err(|e| e.kind()), + Err(AllocError { .. }), + "isize::MAX + 1 should trigger an OOM!" + ); } // Should always overflow in the add-to-len - if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_USIZE) { - } else { - panic!("usize::MAX should trigger an overflow!") - } + assert_matches!( + ten_bytes.try_reserve(MAX_USIZE).map_err(|e| e.kind()), + Err(CapacityOverflow), + "usize::MAX should trigger an overflow!" + ); } { // Same basic idea, but with interesting type size let mut ten_u32s: VecDeque<u32> = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10].into_iter().collect(); - if let Err(CapacityOverflow) = ten_u32s.try_reserve(MAX_CAP / 4 - 10) { + if let Err(CapacityOverflow) = ten_u32s.try_reserve(MAX_CAP / 4 - 10).map_err(|e| e.kind()) + { panic!("isize::MAX shouldn't trigger an overflow!"); } - if let Err(CapacityOverflow) = ten_u32s.try_reserve(MAX_CAP / 4 - 10) { + if let Err(CapacityOverflow) = ten_u32s.try_reserve(MAX_CAP / 4 - 10).map_err(|e| e.kind()) + { panic!("isize::MAX shouldn't trigger an overflow!"); } if guards_against_isize { - if let Err(CapacityOverflow) = ten_u32s.try_reserve(MAX_CAP / 4 - 9) { - } else { - panic!("isize::MAX + 1 should trigger an overflow!"); - } + assert_matches!( + ten_u32s.try_reserve(MAX_CAP / 4 - 9).map_err(|e| e.kind()), + Err(CapacityOverflow), + "isize::MAX + 1 should trigger an overflow!" + ); } else { - if let Err(AllocError { .. }) = ten_u32s.try_reserve(MAX_CAP / 4 - 9) { - } else { - panic!("isize::MAX + 1 should trigger an OOM!") - } + assert_matches!( + ten_u32s.try_reserve(MAX_CAP / 4 - 9).map_err(|e| e.kind()), + Err(AllocError { .. }), + "isize::MAX + 1 should trigger an OOM!" + ); } // Should fail in the mul-by-size - if let Err(CapacityOverflow) = ten_u32s.try_reserve(MAX_USIZE - 20) { - } else { - panic!("usize::MAX should trigger an overflow!"); - } + assert_matches!( + ten_u32s.try_reserve(MAX_USIZE - 20).map_err(|e| e.kind()), + Err(CapacityOverflow), + "usize::MAX should trigger an overflow!" + ); } } @@ -1275,85 +1287,104 @@ fn test_try_reserve_exact() { { let mut empty_bytes: VecDeque<u8> = VecDeque::new(); - if let Err(CapacityOverflow) = empty_bytes.try_reserve_exact(MAX_CAP) { + if let Err(CapacityOverflow) = empty_bytes.try_reserve_exact(MAX_CAP).map_err(|e| e.kind()) + { panic!("isize::MAX shouldn't trigger an overflow!"); } - if let Err(CapacityOverflow) = empty_bytes.try_reserve_exact(MAX_CAP) { + if let Err(CapacityOverflow) = empty_bytes.try_reserve_exact(MAX_CAP).map_err(|e| e.kind()) + { panic!("isize::MAX shouldn't trigger an overflow!"); } if guards_against_isize { - if let Err(CapacityOverflow) = empty_bytes.try_reserve_exact(MAX_CAP + 1) { - } else { - panic!("isize::MAX + 1 should trigger an overflow!") - } - - if let Err(CapacityOverflow) = empty_bytes.try_reserve_exact(MAX_USIZE) { - } else { - panic!("usize::MAX should trigger an overflow!") - } + assert_matches!( + empty_bytes.try_reserve_exact(MAX_CAP + 1).map_err(|e| e.kind()), + Err(CapacityOverflow), + "isize::MAX + 1 should trigger an overflow!" + ); + + assert_matches!( + empty_bytes.try_reserve_exact(MAX_USIZE).map_err(|e| e.kind()), + Err(CapacityOverflow), + "usize::MAX should trigger an overflow!" + ); } else { // Check isize::MAX is an OOM // VecDeque starts with capacity 7, always adds 1 to the capacity // and also rounds the number to next power of 2 so this is the // furthest we can go without triggering CapacityOverflow - if let Err(AllocError { .. }) = empty_bytes.try_reserve_exact(MAX_CAP) { - } else { - panic!("isize::MAX + 1 should trigger an OOM!") - } + assert_matches!( + empty_bytes.try_reserve_exact(MAX_CAP).map_err(|e| e.kind()), + Err(AllocError { .. }), + "isize::MAX + 1 should trigger an OOM!" + ); } } { let mut ten_bytes: VecDeque<u8> = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10].into_iter().collect(); - if let Err(CapacityOverflow) = ten_bytes.try_reserve_exact(MAX_CAP - 10) { + if let Err(CapacityOverflow) = + ten_bytes.try_reserve_exact(MAX_CAP - 10).map_err(|e| e.kind()) + { panic!("isize::MAX shouldn't trigger an overflow!"); } - if let Err(CapacityOverflow) = ten_bytes.try_reserve_exact(MAX_CAP - 10) { + if let Err(CapacityOverflow) = + ten_bytes.try_reserve_exact(MAX_CAP - 10).map_err(|e| e.kind()) + { panic!("isize::MAX shouldn't trigger an overflow!"); } if guards_against_isize { - if let Err(CapacityOverflow) = ten_bytes.try_reserve_exact(MAX_CAP - 9) { - } else { - panic!("isize::MAX + 1 should trigger an overflow!"); - } + assert_matches!( + ten_bytes.try_reserve_exact(MAX_CAP - 9).map_err(|e| e.kind()), + Err(CapacityOverflow), + "isize::MAX + 1 should trigger an overflow!" + ); } else { - if let Err(AllocError { .. }) = ten_bytes.try_reserve_exact(MAX_CAP - 9) { - } else { - panic!("isize::MAX + 1 should trigger an OOM!") - } - } - if let Err(CapacityOverflow) = ten_bytes.try_reserve_exact(MAX_USIZE) { - } else { - panic!("usize::MAX should trigger an overflow!") + assert_matches!( + ten_bytes.try_reserve_exact(MAX_CAP - 9).map_err(|e| e.kind()), + Err(AllocError { .. }), + "isize::MAX + 1 should trigger an OOM!" + ); } + assert_matches!( + ten_bytes.try_reserve_exact(MAX_USIZE).map_err(|e| e.kind()), + Err(CapacityOverflow), + "usize::MAX should trigger an overflow!" + ); } { let mut ten_u32s: VecDeque<u32> = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10].into_iter().collect(); - if let Err(CapacityOverflow) = ten_u32s.try_reserve_exact(MAX_CAP / 4 - 10) { + if let Err(CapacityOverflow) = + ten_u32s.try_reserve_exact(MAX_CAP / 4 - 10).map_err(|e| e.kind()) + { panic!("isize::MAX shouldn't trigger an overflow!"); } - if let Err(CapacityOverflow) = ten_u32s.try_reserve_exact(MAX_CAP / 4 - 10) { + if let Err(CapacityOverflow) = + ten_u32s.try_reserve_exact(MAX_CAP / 4 - 10).map_err(|e| e.kind()) + { panic!("isize::MAX shouldn't trigger an overflow!"); } if guards_against_isize { - if let Err(CapacityOverflow) = ten_u32s.try_reserve_exact(MAX_CAP / 4 - 9) { - } else { - panic!("isize::MAX + 1 should trigger an overflow!"); - } - } else { - if let Err(AllocError { .. }) = ten_u32s.try_reserve_exact(MAX_CAP / 4 - 9) { - } else { - panic!("isize::MAX + 1 should trigger an OOM!") - } - } - if let Err(CapacityOverflow) = ten_u32s.try_reserve_exact(MAX_USIZE - 20) { + assert_matches!( + ten_u32s.try_reserve_exact(MAX_CAP / 4 - 9).map_err(|e| e.kind()), + Err(CapacityOverflow), + "isize::MAX + 1 should trigger an overflow!" + ); } else { - panic!("usize::MAX should trigger an overflow!") + assert_matches!( + ten_u32s.try_reserve_exact(MAX_CAP / 4 - 9).map_err(|e| e.kind()), + Err(AllocError { .. }), + "isize::MAX + 1 should trigger an OOM!" + ); } + assert_matches!( + ten_u32s.try_reserve_exact(MAX_USIZE - 20).map_err(|e| e.kind()), + Err(CapacityOverflow), + "usize::MAX should trigger an overflow!" + ); } } diff --git a/library/core/Cargo.toml b/library/core/Cargo.toml index b6aaf078cf0..6f10b9e4342 100644 --- a/library/core/Cargo.toml +++ b/library/core/Cargo.toml @@ -1,5 +1,4 @@ [package] -authors = ["The Rust Project Developers"] name = "core" version = "0.0.0" license = "MIT OR Apache-2.0" diff --git a/library/core/benches/iter.rs b/library/core/benches/iter.rs index f2169914ac9..24257ba9878 100644 --- a/library/core/benches/iter.rs +++ b/library/core/benches/iter.rs @@ -45,7 +45,7 @@ fn bench_max_by_key(b: &mut Bencher) { }) } -// http://www.reddit.com/r/rust/comments/31syce/using_iterators_to_find_the_index_of_the_min_or/ +// https://www.reddit.com/r/rust/comments/31syce/using_iterators_to_find_the_index_of_the_min_or/ #[bench] fn bench_max_by_key2(b: &mut Bencher) { fn max_index_iter(array: &[i32]) -> usize { diff --git a/library/core/src/alloc/global.rs b/library/core/src/alloc/global.rs index 6dcc110f153..8839a69d119 100644 --- a/library/core/src/alloc/global.rs +++ b/library/core/src/alloc/global.rs @@ -20,24 +20,69 @@ use crate::ptr; /// /// # Example /// -/// ```no_run -/// use std::alloc::{GlobalAlloc, Layout, alloc}; +/// ``` +/// use std::alloc::{GlobalAlloc, Layout}; +/// use std::cell::UnsafeCell; /// use std::ptr::null_mut; +/// use std::sync::atomic::{ +/// AtomicUsize, +/// Ordering::{Acquire, SeqCst}, +/// }; /// -/// struct MyAllocator; -/// -/// unsafe impl GlobalAlloc for MyAllocator { -/// unsafe fn alloc(&self, _layout: Layout) -> *mut u8 { null_mut() } -/// unsafe fn dealloc(&self, _ptr: *mut u8, _layout: Layout) {} +/// const ARENA_SIZE: usize = 128 * 1024; +/// const MAX_SUPPORTED_ALIGN: usize = 4096; +/// #[repr(C, align(4096))] // 4096 == MAX_SUPPORTED_ALIGN +/// struct SimpleAllocator { +/// arena: UnsafeCell<[u8; ARENA_SIZE]>, +/// remaining: AtomicUsize, // we allocate from the top, counting down /// } /// /// #[global_allocator] -/// static A: MyAllocator = MyAllocator; +/// static ALLOCATOR: SimpleAllocator = SimpleAllocator { +/// arena: UnsafeCell::new([0x55; ARENA_SIZE]), +/// remaining: AtomicUsize::new(ARENA_SIZE), +/// }; /// -/// fn main() { -/// unsafe { -/// assert!(alloc(Layout::new::<u32>()).is_null()) +/// unsafe impl Sync for SimpleAllocator {} +/// +/// unsafe impl GlobalAlloc for SimpleAllocator { +/// unsafe fn alloc(&self, layout: Layout) -> *mut u8 { +/// let size = layout.size(); +/// let align = layout.align(); +/// +/// // `Layout` contract forbids making a `Layout` with align=0, or align not power of 2. +/// // So we can safely use a mask to ensure alignment without worrying about UB. +/// let align_mask_to_round_down = !(align - 1); +/// +/// if align > MAX_SUPPORTED_ALIGN { +/// return null_mut(); +/// } +/// +/// let mut allocated = 0; +/// if self +/// .remaining +/// .fetch_update(SeqCst, SeqCst, |mut remaining| { +/// if size > remaining { +/// return None; +/// } +/// remaining -= size; +/// remaining &= align_mask_to_round_down; +/// allocated = remaining; +/// Some(remaining) +/// }) +/// .is_err() +/// { +/// return null_mut(); +/// }; +/// (self.arena.get() as *mut u8).add(allocated) /// } +/// unsafe fn dealloc(&self, _ptr: *mut u8, _layout: Layout) {} +/// } +/// +/// fn main() { +/// let _s = format!("allocating a string!"); +/// let currently = ALLOCATOR.remaining.load(Acquire); +/// println!("allocated so far: {}", ARENA_SIZE - currently); /// } /// ``` /// @@ -54,7 +99,7 @@ use crate::ptr; /// this trait are allowed to rely on the contracts defined on each method, /// and implementors must ensure such contracts remain true. /// -/// * You may not rely on allocations actually happening, even if there are explicit +/// * You must not rely on allocations actually happening, even if there are explicit /// heap allocations in the source. The optimizer may detect unused allocations that it can either /// eliminate entirely or move to the stack and thus never invoke the allocator. The /// optimizer may further assume that allocation is infallible, so code that used to fail due diff --git a/library/core/src/alloc/layout.rs b/library/core/src/alloc/layout.rs index 0e7667dd89e..ccf6e420de7 100644 --- a/library/core/src/alloc/layout.rs +++ b/library/core/src/alloc/layout.rs @@ -60,7 +60,7 @@ impl Layout { #[inline] pub const fn from_size_align(size: usize, align: usize) -> Result<Self, LayoutError> { if !align.is_power_of_two() { - return Err(LayoutError { private: () }); + return Err(LayoutError); } // (power-of-two implies align != 0.) @@ -78,7 +78,7 @@ impl Layout { // Above implies that checking for summation overflow is both // necessary and sufficient. if size > usize::MAX - (align - 1) { - return Err(LayoutError { private: () }); + return Err(LayoutError); } // SAFETY: the conditions for `from_size_align_unchecked` have been @@ -288,7 +288,7 @@ impl Layout { // > must not overflow (i.e., the rounded value must be less than // > `usize::MAX`) let padded_size = self.size() + self.padding_needed_for(self.align()); - let alloc_size = padded_size.checked_mul(n).ok_or(LayoutError { private: () })?; + let alloc_size = padded_size.checked_mul(n).ok_or(LayoutError)?; // SAFETY: self.align is already known to be valid and alloc_size has been // padded already. @@ -346,8 +346,8 @@ impl Layout { let new_align = cmp::max(self.align(), next.align()); let pad = self.padding_needed_for(next.align()); - let offset = self.size().checked_add(pad).ok_or(LayoutError { private: () })?; - let new_size = offset.checked_add(next.size()).ok_or(LayoutError { private: () })?; + let offset = self.size().checked_add(pad).ok_or(LayoutError)?; + let new_size = offset.checked_add(next.size()).ok_or(LayoutError)?; let layout = Layout::from_size_align(new_size, new_align)?; Ok((layout, offset)) @@ -368,7 +368,7 @@ impl Layout { #[unstable(feature = "alloc_layout_extra", issue = "55724")] #[inline] pub fn repeat_packed(&self, n: usize) -> Result<Self, LayoutError> { - let size = self.size().checked_mul(n).ok_or(LayoutError { private: () })?; + let size = self.size().checked_mul(n).ok_or(LayoutError)?; Layout::from_size_align(size, self.align()) } @@ -381,7 +381,7 @@ impl Layout { #[unstable(feature = "alloc_layout_extra", issue = "55724")] #[inline] pub fn extend_packed(&self, next: Self) -> Result<Self, LayoutError> { - let new_size = self.size().checked_add(next.size()).ok_or(LayoutError { private: () })?; + let new_size = self.size().checked_add(next.size()).ok_or(LayoutError)?; Layout::from_size_align(new_size, self.align()) } @@ -409,10 +409,9 @@ pub type LayoutErr = LayoutError; /// or some other `Layout` constructor /// do not satisfy its documented constraints. #[stable(feature = "alloc_layout_error", since = "1.50.0")] +#[non_exhaustive] #[derive(Clone, PartialEq, Eq, Debug)] -pub struct LayoutError { - private: (), -} +pub struct LayoutError; // (we need this for downstream impl of trait Error) #[stable(feature = "alloc_layout", since = "1.28.0")] diff --git a/library/core/src/alloc/mod.rs b/library/core/src/alloc/mod.rs index 06a761531b6..1f1033b0437 100644 --- a/library/core/src/alloc/mod.rs +++ b/library/core/src/alloc/mod.rs @@ -338,9 +338,9 @@ pub unsafe trait Allocator { Ok(new_ptr) } - /// Creates a "by reference" adaptor for this instance of `Allocator`. + /// Creates a "by reference" adapter for this instance of `Allocator`. /// - /// The returned adaptor also implements `Allocator` and will simply borrow this. + /// The returned adapter also implements `Allocator` and will simply borrow this. #[inline(always)] fn by_ref(&self) -> &Self where diff --git a/library/core/src/any.rs b/library/core/src/any.rs index 5e1725cfc7a..19652106b3d 100644 --- a/library/core/src/any.rs +++ b/library/core/src/any.rs @@ -108,6 +108,7 @@ use crate::intrinsics; // unsafe traits and unsafe methods (i.e., `type_id` would still be safe to call, // but we would likely want to indicate as such in documentation). #[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr(not(test), rustc_diagnostic_item = "Any")] pub trait Any: 'static { /// Gets the `TypeId` of `self`. /// diff --git a/library/core/src/array/equality.rs b/library/core/src/array/equality.rs new file mode 100644 index 00000000000..a882d18b151 --- /dev/null +++ b/library/core/src/array/equality.rs @@ -0,0 +1,155 @@ +#[stable(feature = "rust1", since = "1.0.0")] +impl<A, B, const N: usize> PartialEq<[B; N]> for [A; N] +where + A: PartialEq<B>, +{ + #[inline] + fn eq(&self, other: &[B; N]) -> bool { + SpecArrayEq::spec_eq(self, other) + } + #[inline] + fn ne(&self, other: &[B; N]) -> bool { + SpecArrayEq::spec_ne(self, other) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<A, B, const N: usize> PartialEq<[B]> for [A; N] +where + A: PartialEq<B>, +{ + #[inline] + fn eq(&self, other: &[B]) -> bool { + self[..] == other[..] + } + #[inline] + fn ne(&self, other: &[B]) -> bool { + self[..] != other[..] + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<A, B, const N: usize> PartialEq<[A; N]> for [B] +where + B: PartialEq<A>, +{ + #[inline] + fn eq(&self, other: &[A; N]) -> bool { + self[..] == other[..] + } + #[inline] + fn ne(&self, other: &[A; N]) -> bool { + self[..] != other[..] + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<A, B, const N: usize> PartialEq<&[B]> for [A; N] +where + A: PartialEq<B>, +{ + #[inline] + fn eq(&self, other: &&[B]) -> bool { + self[..] == other[..] + } + #[inline] + fn ne(&self, other: &&[B]) -> bool { + self[..] != other[..] + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<A, B, const N: usize> PartialEq<[A; N]> for &[B] +where + B: PartialEq<A>, +{ + #[inline] + fn eq(&self, other: &[A; N]) -> bool { + self[..] == other[..] + } + #[inline] + fn ne(&self, other: &[A; N]) -> bool { + self[..] != other[..] + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<A, B, const N: usize> PartialEq<&mut [B]> for [A; N] +where + A: PartialEq<B>, +{ + #[inline] + fn eq(&self, other: &&mut [B]) -> bool { + self[..] == other[..] + } + #[inline] + fn ne(&self, other: &&mut [B]) -> bool { + self[..] != other[..] + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<A, B, const N: usize> PartialEq<[A; N]> for &mut [B] +where + B: PartialEq<A>, +{ + #[inline] + fn eq(&self, other: &[A; N]) -> bool { + self[..] == other[..] + } + #[inline] + fn ne(&self, other: &[A; N]) -> bool { + self[..] != other[..] + } +} + +// NOTE: some less important impls are omitted to reduce code bloat +// __impl_slice_eq2! { [A; $N], &'b [B; $N] } +// __impl_slice_eq2! { [A; $N], &'b mut [B; $N] } + +#[stable(feature = "rust1", since = "1.0.0")] +impl<T: Eq, const N: usize> Eq for [T; N] {} + +trait SpecArrayEq<Other, const N: usize>: Sized { + fn spec_eq(a: &[Self; N], b: &[Other; N]) -> bool; + fn spec_ne(a: &[Self; N], b: &[Other; N]) -> bool; +} + +impl<T: PartialEq<Other>, Other, const N: usize> SpecArrayEq<Other, N> for T { + default fn spec_eq(a: &[Self; N], b: &[Other; N]) -> bool { + a[..] == b[..] + } + default fn spec_ne(a: &[Self; N], b: &[Other; N]) -> bool { + a[..] != b[..] + } +} + +impl<T: PartialEq<U> + IsRawEqComparable<U>, U, const N: usize> SpecArrayEq<U, N> for T { + fn spec_eq(a: &[T; N], b: &[U; N]) -> bool { + // SAFETY: This is why `IsRawEqComparable` is an `unsafe trait`. + unsafe { + let b = &*b.as_ptr().cast::<[T; N]>(); + crate::intrinsics::raw_eq(a, b) + } + } + fn spec_ne(a: &[T; N], b: &[U; N]) -> bool { + !Self::spec_eq(a, b) + } +} + +/// `U` exists on here mostly because `min_specialization` didn't let me +/// repeat the `T` type parameter in the above specialization, so instead +/// the `T == U` constraint comes from the impls on this. +/// # Safety +/// - Neither `Self` nor `U` has any padding. +/// - `Self` and `U` have the same layout. +/// - `Self: PartialEq<U>` is byte-wise (this means no floats, among other things) +#[rustc_specialization_trait] +unsafe trait IsRawEqComparable<U> {} + +macro_rules! is_raw_comparable { + ($($t:ty),+) => {$( + unsafe impl IsRawEqComparable<$t> for $t {} + )+}; +} +is_raw_comparable!(bool, char, u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize); diff --git a/library/core/src/array/iter.rs b/library/core/src/array/iter.rs index aedbeab6610..f6616399610 100644 --- a/library/core/src/array/iter.rs +++ b/library/core/src/array/iter.rs @@ -2,7 +2,7 @@ use crate::{ fmt, - iter::{self, ExactSizeIterator, FusedIterator, TrustedLen, TrustedRandomAccess}, + iter::{self, ExactSizeIterator, FusedIterator, TrustedLen}, mem::{self, MaybeUninit}, ops::Range, ptr, @@ -123,6 +123,27 @@ impl<T, const N: usize> Iterator for IntoIter<T, N> { (len, Some(len)) } + #[inline] + fn fold<Acc, Fold>(mut self, init: Acc, mut fold: Fold) -> Acc + where + Fold: FnMut(Acc, Self::Item) -> Acc, + { + let data = &mut self.data; + // FIXME: This uses try_fold(&mut iter) instead of fold(iter) because the latter + // would go through the blanket `impl Iterator for &mut I` implementation + // which lacks inline annotations on its methods and adding those would be a larger + // perturbation than using try_fold here. + // Whether it would be beneficial to add those annotations should be investigated separately. + (&mut self.alive) + .try_fold::<_, _, Result<_, !>>(init, |acc, idx| { + // SAFETY: idx is obtained by folding over the `alive` range, which implies the + // value is currently considered alive but as the range is being consumed each value + // we read here will only be read once and then considered dead. + Ok(fold(acc, unsafe { data.get_unchecked(idx).assume_init_read() })) + }) + .unwrap() + } + fn count(self) -> usize { self.len() } @@ -130,18 +151,6 @@ impl<T, const N: usize> Iterator for IntoIter<T, N> { fn last(mut self) -> Option<Self::Item> { self.next_back() } - - #[inline] - unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item - where - Self: TrustedRandomAccess, - { - // SAFETY: Callers are only allowed to pass an index that is in bounds - // Additionally Self: TrustedRandomAccess is only implemented for T: Copy which means even - // multiple repeated reads of the same index would be safe and the - // values are !Drop, thus won't suffer from double drops. - unsafe { self.data.get_unchecked(self.alive.start + idx).assume_init_read() } - } } #[stable(feature = "array_value_iter_impls", since = "1.40.0")] @@ -196,17 +205,6 @@ impl<T, const N: usize> FusedIterator for IntoIter<T, N> {} #[stable(feature = "array_value_iter_impls", since = "1.40.0")] unsafe impl<T, const N: usize> TrustedLen for IntoIter<T, N> {} -#[doc(hidden)] -#[unstable(feature = "trusted_random_access", issue = "none")] -// T: Copy as approximation for !Drop since get_unchecked does not update the pointers -// and thus we can't implement drop-handling -unsafe impl<T, const N: usize> TrustedRandomAccess for IntoIter<T, N> -where - T: Copy, -{ - const MAY_HAVE_SIDE_EFFECT: bool = false; -} - #[stable(feature = "array_value_iter_impls", since = "1.40.0")] impl<T: Clone, const N: usize> Clone for IntoIter<T, N> { fn clone(&self) -> Self { diff --git a/library/core/src/array/mod.rs b/library/core/src/array/mod.rs index 37af3557fdd..3c638e655dc 100644 --- a/library/core/src/array/mod.rs +++ b/library/core/src/array/mod.rs @@ -14,6 +14,7 @@ use crate::mem::{self, MaybeUninit}; use crate::ops::{Index, IndexMut}; use crate::slice::{Iter, IterMut}; +mod equality; mod iter; #[stable(feature = "array_value_iter", since = "1.51.0")] @@ -139,6 +140,18 @@ impl<'a, T, const N: usize> TryFrom<&'a mut [T]> for &'a mut [T; N] { } } +/// The hash of an array is the same as that of the corresponding slice, +/// as required by the `Borrow` implementation. +/// +/// ``` +/// #![feature(build_hasher_simple_hash_one)] +/// use std::hash::BuildHasher; +/// +/// let b = std::collections::hash_map::RandomState::new(); +/// let a: [u8; 3] = [0xa8, 0x3c, 0x09]; +/// let s: &[u8] = &[0xa8, 0x3c, 0x09]; +/// assert_eq!(b.hash_one(a), b.hash_one(s)); +/// ``` #[stable(feature = "rust1", since = "1.0.0")] impl<T: Hash, const N: usize> Hash for [T; N] { fn hash<H: hash::Hasher>(&self, state: &mut H) { @@ -219,118 +232,6 @@ where } #[stable(feature = "rust1", since = "1.0.0")] -impl<A, B, const N: usize> PartialEq<[B; N]> for [A; N] -where - A: PartialEq<B>, -{ - #[inline] - fn eq(&self, other: &[B; N]) -> bool { - self[..] == other[..] - } - #[inline] - fn ne(&self, other: &[B; N]) -> bool { - self[..] != other[..] - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<A, B, const N: usize> PartialEq<[B]> for [A; N] -where - A: PartialEq<B>, -{ - #[inline] - fn eq(&self, other: &[B]) -> bool { - self[..] == other[..] - } - #[inline] - fn ne(&self, other: &[B]) -> bool { - self[..] != other[..] - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<A, B, const N: usize> PartialEq<[A; N]> for [B] -where - B: PartialEq<A>, -{ - #[inline] - fn eq(&self, other: &[A; N]) -> bool { - self[..] == other[..] - } - #[inline] - fn ne(&self, other: &[A; N]) -> bool { - self[..] != other[..] - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<A, B, const N: usize> PartialEq<&[B]> for [A; N] -where - A: PartialEq<B>, -{ - #[inline] - fn eq(&self, other: &&[B]) -> bool { - self[..] == other[..] - } - #[inline] - fn ne(&self, other: &&[B]) -> bool { - self[..] != other[..] - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<A, B, const N: usize> PartialEq<[A; N]> for &[B] -where - B: PartialEq<A>, -{ - #[inline] - fn eq(&self, other: &[A; N]) -> bool { - self[..] == other[..] - } - #[inline] - fn ne(&self, other: &[A; N]) -> bool { - self[..] != other[..] - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<A, B, const N: usize> PartialEq<&mut [B]> for [A; N] -where - A: PartialEq<B>, -{ - #[inline] - fn eq(&self, other: &&mut [B]) -> bool { - self[..] == other[..] - } - #[inline] - fn ne(&self, other: &&mut [B]) -> bool { - self[..] != other[..] - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<A, B, const N: usize> PartialEq<[A; N]> for &mut [B] -where - B: PartialEq<A>, -{ - #[inline] - fn eq(&self, other: &[A; N]) -> bool { - self[..] == other[..] - } - #[inline] - fn ne(&self, other: &[A; N]) -> bool { - self[..] != other[..] - } -} - -// NOTE: some less important impls are omitted to reduce code bloat -// __impl_slice_eq2! { [A; $N], &'b [B; $N] } -// __impl_slice_eq2! { [A; $N], &'b mut [B; $N] } - -#[stable(feature = "rust1", since = "1.0.0")] -impl<T: Eq, const N: usize> Eq for [T; N] {} - -#[stable(feature = "rust1", since = "1.0.0")] impl<T: PartialOrd, const N: usize> PartialOrd for [T; N] { #[inline] fn partial_cmp(&self, other: &[T; N]) -> Option<Ordering> { @@ -379,7 +280,8 @@ macro_rules! array_impl_default { }; {$n:expr,} => { #[stable(since = "1.4.0", feature = "array_default")] - impl<T> Default for [T; $n] { + #[rustc_const_unstable(feature = "const_default_impls", issue = "87864")] + impl<T> const Default for [T; $n] { fn default() -> [T; $n] { [] } } }; @@ -392,10 +294,31 @@ impl<T, const N: usize> [T; N] { /// Returns an array of the same size as `self`, with function `f` applied to each element /// in order. /// + /// If you don't necessarily need a new fixed-size array, consider using + /// [`Iterator::map`] instead. + /// + /// + /// # Note on performance and stack usage + /// + /// Unfortunately, usages of this method are currently not always optimized + /// as well as they could be. This mainly concerns large arrays, as mapping + /// over small arrays seem to be optimized just fine. Also note that in + /// debug mode (i.e. without any optimizations), this method can use a lot + /// of stack space (a few times the size of the array or more). + /// + /// Therefore, in performance-critical code, try to avoid using this method + /// on large arrays or check the emitted code. Also try to avoid chained + /// maps (e.g. `arr.map(...).map(...)`). + /// + /// In many cases, you can instead use [`Iterator::map`] by calling `.iter()` + /// or `.into_iter()` on your array. `[T; N]::map` is only necessary if you + /// really need a new array of the same size as the result. Rust's lazy + /// iterators tend to get optimized very well. + /// + /// /// # Examples /// /// ``` - /// #![feature(array_map)] /// let x = [1, 2, 3]; /// let y = x.map(|v| v + 1); /// assert_eq!(y, [2, 3, 4]); @@ -409,7 +332,7 @@ impl<T, const N: usize> [T; N] { /// let y = x.map(|v| v.len()); /// assert_eq!(y, [6, 9, 3, 3]); /// ``` - #[unstable(feature = "array_map", issue = "75243")] + #[stable(feature = "array_map", since = "1.55.0")] pub fn map<F, U>(self, f: F) -> [U; N] where F: FnMut(T) -> U, @@ -476,7 +399,7 @@ impl<T, const N: usize> [T; N] { /// array if its elements are not `Copy`. /// /// ``` - /// #![feature(array_methods, array_map)] + /// #![feature(array_methods)] /// /// let strings = ["Ferris".to_string(), "♥".to_string(), "Rust".to_string()]; /// let is_ascii = strings.each_ref().map(|s| s.is_ascii()); diff --git a/library/core/src/bool.rs b/library/core/src/bool.rs index 00164c631b3..dcafaae2f5b 100644 --- a/library/core/src/bool.rs +++ b/library/core/src/bool.rs @@ -12,7 +12,7 @@ impl bool { /// assert_eq!(false.then_some(0), None); /// assert_eq!(true.then_some(0), Some(0)); /// ``` - #[unstable(feature = "bool_to_option", issue = "64260")] + #[unstable(feature = "bool_to_option", issue = "80967")] #[inline] pub fn then_some<T>(self, t: T) -> Option<T> { if self { Some(t) } else { None } diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs index f88a6e418c7..f0c934edf39 100644 --- a/library/core/src/cell.rs +++ b/library/core/src/cell.rs @@ -488,6 +488,13 @@ impl<T: ?Sized> Cell<T> { /// This call borrows `Cell` mutably (at compile-time) which guarantees /// that we possess the only reference. /// + /// However be cautious: this method expects `self` to be mutable, which is + /// generally not the case when using a `Cell`. If you require interior + /// mutability by reference, consider using `RefCell` which provides + /// run-time checked mutable borrows through its [`borrow_mut`] method. + /// + /// [`borrow_mut`]: RefCell::borrow_mut() + /// /// # Examples /// /// ``` @@ -576,9 +583,9 @@ impl<T> Cell<[T]> { pub struct RefCell<T: ?Sized> { borrow: Cell<BorrowFlag>, // Stores the location of the earliest currently active borrow. - // This gets updated whenver we go from having zero borrows + // This gets updated whenever we go from having zero borrows // to having a single borrow. When a borrow occurs, this gets included - // in the generated `BorroeError/`BorrowMutError` + // in the generated `BorrowError/`BorrowMutError` #[cfg(feature = "debug_refcell")] borrowed_at: Cell<Option<&'static crate::panic::Location<'static>>>, value: UnsafeCell<T>, @@ -586,8 +593,8 @@ pub struct RefCell<T: ?Sized> { /// An error returned by [`RefCell::try_borrow`]. #[stable(feature = "try_borrow", since = "1.13.0")] +#[non_exhaustive] pub struct BorrowError { - _private: (), #[cfg(feature = "debug_refcell")] location: &'static crate::panic::Location<'static>, } @@ -613,8 +620,8 @@ impl Display for BorrowError { /// An error returned by [`RefCell::try_borrow_mut`]. #[stable(feature = "try_borrow", since = "1.13.0")] +#[non_exhaustive] pub struct BorrowMutError { - _private: (), #[cfg(feature = "debug_refcell")] location: &'static crate::panic::Location<'static>, } @@ -865,7 +872,6 @@ impl<T: ?Sized> RefCell<T> { Ok(Ref { value: unsafe { &*self.value.get() }, borrow: b }) } None => Err(BorrowError { - _private: (), // If a borrow occured, then we must already have an outstanding borrow, // so `borrowed_at` will be `Some` #[cfg(feature = "debug_refcell")] @@ -951,7 +957,6 @@ impl<T: ?Sized> RefCell<T> { Ok(RefMut { value: unsafe { &mut *self.value.get() }, borrow: b }) } None => Err(BorrowMutError { - _private: (), // If a borrow occured, then we must already have an outstanding borrow, // so `borrowed_at` will be `Some` #[cfg(feature = "debug_refcell")] @@ -1073,7 +1078,6 @@ impl<T: ?Sized> RefCell<T> { Ok(unsafe { &*self.value.get() }) } else { Err(BorrowError { - _private: (), // If a borrow occured, then we must already have an outstanding borrow, // so `borrowed_at` will be `Some` #[cfg(feature = "debug_refcell")] diff --git a/library/core/src/char/decode.rs b/library/core/src/char/decode.rs index 5e7784730e3..4784418f98c 100644 --- a/library/core/src/char/decode.rs +++ b/library/core/src/char/decode.rs @@ -5,6 +5,11 @@ use crate::fmt; use super::from_u32_unchecked; /// An iterator that decodes UTF-16 encoded code points from an iterator of `u16`s. +/// +/// This `struct` is created by the [`decode_utf16`] method on [`char`]. See its +/// documentation for more. +/// +/// [`decode_utf16`]: char::decode_utf16 #[stable(feature = "decode_utf16", since = "1.9.0")] #[derive(Clone, Debug)] pub struct DecodeUtf16<I> @@ -16,6 +21,8 @@ where } /// An error that can be returned when decoding UTF-16 code points. +/// +/// This `struct` is created when using the [`DecodeUtf16`] type. #[stable(feature = "decode_utf16", since = "1.9.0")] #[derive(Debug, Clone, Eq, PartialEq)] pub struct DecodeUtf16Error { diff --git a/library/core/src/char/methods.rs b/library/core/src/char/methods.rs index 2da3d6a72fb..e5af22c8fbb 100644 --- a/library/core/src/char/methods.rs +++ b/library/core/src/char/methods.rs @@ -1,6 +1,5 @@ //! impl char {} -use crate::intrinsics::likely; use crate::slice; use crate::str::from_utf8_unchecked_mut; use crate::unicode::printable::is_printable; @@ -16,8 +15,8 @@ impl char { /// Point], but only ones within a certain range. `MAX` is the highest valid /// code point that's a valid [Unicode Scalar Value]. /// - /// [Unicode Scalar Value]: http://www.unicode.org/glossary/#unicode_scalar_value - /// [Code Point]: http://www.unicode.org/glossary/#code_point + /// [Unicode Scalar Value]: https://www.unicode.org/glossary/#unicode_scalar_value + /// [Code Point]: https://www.unicode.org/glossary/#code_point #[stable(feature = "assoc_char_consts", since = "1.52.0")] pub const MAX: char = '\u{10ffff}'; @@ -29,7 +28,7 @@ impl char { #[stable(feature = "assoc_char_consts", since = "1.52.0")] pub const REPLACEMENT_CHARACTER: char = '\u{FFFD}'; - /// The version of [Unicode](http://www.unicode.org/) that the Unicode parts of + /// The version of [Unicode](https://www.unicode.org/) that the Unicode parts of /// `char` and `str` methods are based on. /// /// New versions of Unicode are released regularly and subsequently all methods @@ -332,21 +331,16 @@ impl char { #[inline] pub fn to_digit(self, radix: u32) -> Option<u32> { assert!(radix <= 36, "to_digit: radix is too high (maximum 36)"); - // the code is split up here to improve execution speed for cases where - // the `radix` is constant and 10 or smaller - let val = if likely(radix <= 10) { - // If not a digit, a number greater than radix will be created. - (self as u32).wrapping_sub('0' as u32) - } else { - match self { - '0'..='9' => self as u32 - '0' as u32, - 'a'..='z' => self as u32 - 'a' as u32 + 10, - 'A'..='Z' => self as u32 - 'A' as u32 + 10, - _ => return None, + // If not a digit, a number greater than radix will be created. + let mut digit = (self as u32).wrapping_sub('0' as u32); + if radix > 10 { + if digit < 10 { + return Some(digit); } - }; - - if val < radix { Some(val) } else { None } + // Force the 6th bit to be set to ensure ascii is lower case. + digit = (self as u32 | 0b10_0000).wrapping_sub('a' as u32).saturating_add(10); + } + (digit < radix).then_some(digit) } /// Returns an iterator that yields the hexadecimal Unicode escape of a @@ -1500,8 +1494,8 @@ impl char { /// before using this function. /// /// [infra-aw]: https://infra.spec.whatwg.org/#ascii-whitespace - /// [pct]: http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap07.html#tag_07_03_01 - /// [bfs]: http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_06_05 + /// [pct]: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap07.html#tag_07_03_01 + /// [bfs]: https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_06_05 /// /// # Examples /// diff --git a/library/core/src/char/mod.rs b/library/core/src/char/mod.rs index 25a7c1de9de..0728523d0a4 100644 --- a/library/core/src/char/mod.rs +++ b/library/core/src/char/mod.rs @@ -5,8 +5,8 @@ //! scalar value]', which is similar to, but not the same as, a '[Unicode code //! point]'. //! -//! [Unicode scalar value]: http://www.unicode.org/glossary/#unicode_scalar_value -//! [Unicode code point]: http://www.unicode.org/glossary/#code_point +//! [Unicode scalar value]: https://www.unicode.org/glossary/#unicode_scalar_value +//! [Unicode code point]: https://www.unicode.org/glossary/#code_point //! //! This module exists for technical reasons, the primary documentation for //! `char` is directly on [the `char` primitive type][char] itself. @@ -95,8 +95,8 @@ const MAX_THREE_B: u32 = 0x10000; /// Point], but only ones within a certain range. `MAX` is the highest valid /// code point that's a valid [Unicode Scalar Value]. /// -/// [Unicode Scalar Value]: http://www.unicode.org/glossary/#unicode_scalar_value -/// [Code Point]: http://www.unicode.org/glossary/#code_point +/// [Unicode Scalar Value]: https://www.unicode.org/glossary/#unicode_scalar_value +/// [Code Point]: https://www.unicode.org/glossary/#code_point #[stable(feature = "rust1", since = "1.0.0")] pub const MAX: char = char::MAX; diff --git a/library/core/src/clone.rs b/library/core/src/clone.rs index 51a2dc03de3..19faf9cddac 100644 --- a/library/core/src/clone.rs +++ b/library/core/src/clone.rs @@ -38,7 +38,7 @@ /// A common trait for the ability to explicitly duplicate an object. /// -/// Differs from [`Copy`] in that [`Copy`] is implicit and extremely inexpensive, while +/// Differs from [`Copy`] in that [`Copy`] is implicit and an inexpensive bit-wise copy, while /// `Clone` is always explicit and may or may not be expensive. In order to enforce /// these characteristics, Rust does not allow you to reimplement [`Copy`], but you /// may reimplement `Clone` and run arbitrary code. diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs index ecea898504d..79610bb409d 100644 --- a/library/core/src/cmp.rs +++ b/library/core/src/cmp.rs @@ -27,12 +27,25 @@ use self::Ordering::*; /// Trait for equality comparisons which are [partial equivalence /// relations](https://en.wikipedia.org/wiki/Partial_equivalence_relation). /// +/// `x.eq(y)` can also be written `x == y`, and `x.ne(y)` can be written `x != y`. +/// We use the easier-to-read infix notation in the remainder of this documentation. +/// /// This trait allows for partial equality, for types that do not have a full /// equivalence relation. For example, in floating point numbers `NaN != NaN`, /// so floating point types implement `PartialEq` but not [`trait@Eq`]. /// -/// Formally, the equality must be (for all `a`, `b`, `c` of type `A`, `B`, -/// `C`): +/// Implementations must ensure that `eq` and `ne` are consistent with each other: +/// +/// - `a != b` if and only if `!(a == b)` +/// (ensured by the default implementation). +/// +/// If [`PartialOrd`] or [`Ord`] are also implemented for `Self` and `Rhs`, their methods must also +/// be consistent with `PartialEq` (see the documentation of those traits for the exact +/// requirements). It's easy to accidentally make them disagree by deriving some of the traits and +/// manually implementing others. +/// +/// The equality relation `==` must satisfy the following conditions +/// (for all `a`, `b`, `c` of type `A`, `B`, `C`): /// /// - **Symmetric**: if `A: PartialEq<B>` and `B: PartialEq<A>`, then **`a == b` /// implies `b == a`**; and @@ -53,15 +66,6 @@ use self::Ordering::*; /// /// ## How can I implement `PartialEq`? /// -/// `PartialEq` only requires the [`eq`] method to be implemented; [`ne`] is defined -/// in terms of it by default. Any manual implementation of [`ne`] *must* respect -/// the rule that [`eq`] is a strict inverse of [`ne`]; that is, `!(a == b)` if and -/// only if `a != b`. -/// -/// Implementations of `PartialEq`, [`PartialOrd`], and [`Ord`] *must* agree with -/// each other. It's easy to accidentally make them disagree by deriving some -/// of the traits and manually implementing others. -/// /// An example implementation for a domain in which two books are considered /// the same book if their ISBN matches, even if the formats differ: /// @@ -631,10 +635,25 @@ impl<T: Clone> Clone for Reverse<T> { /// Trait for types that form a [total order](https://en.wikipedia.org/wiki/Total_order). /// -/// An order is a total order if it is (for all `a`, `b` and `c`): +/// Implementations must be consistent with the [`PartialOrd`] implementation, and ensure +/// `max`, `min`, and `clamp` are consistent with `cmp`: +/// +/// - `partial_cmp(a, b) == Some(cmp(a, b))`. +/// - `max(a, b) == max_by(a, b, cmp)` (ensured by the default implementation). +/// - `min(a, b) == min_by(a, b, cmp)` (ensured by the default implementation). +/// - For `a.clamp(min, max)`, see the [method docs](#method.clamp) +/// (ensured by the default implementation). +/// +/// It's easy to accidentally make `cmp` and `partial_cmp` disagree by +/// deriving some of the traits and manually implementing others. +/// +/// ## Corollaries +/// +/// From the above and the requirements of `PartialOrd`, it follows that `<` defines a strict total order. +/// This means that for all `a`, `b` and `c`: /// -/// - total and asymmetric: exactly one of `a < b`, `a == b` or `a > b` is true; and -/// - transitive, `a < b` and `b < c` implies `a < c`. The same must hold for both `==` and `>`. +/// - exactly one of `a < b`, `a == b` or `a > b` is true; and +/// - `<` is transitive: `a < b` and `b < c` implies `a < c`. The same must hold for both `==` and `>`. /// /// ## Derivable /// @@ -659,12 +678,6 @@ impl<T: Clone> Clone for Reverse<T> { /// Then you must define an implementation for [`cmp`]. You may find it useful to use /// [`cmp`] on your type's fields. /// -/// Implementations of [`PartialEq`], [`PartialOrd`], and `Ord` *must* -/// agree with each other. That is, `a.cmp(b) == Ordering::Equal` if -/// and only if `a == b` and `Some(a.cmp(b)) == a.partial_cmp(b)` for -/// all `a` and `b`. It's easy to accidentally make them disagree by -/// deriving some of the traits and manually implementing others. -/// /// Here's an example where you want to sort people by height only, disregarding `id` /// and `name`: /// @@ -824,15 +837,45 @@ impl PartialOrd for Ordering { /// Trait for values that can be compared for a sort-order. /// +/// The `lt`, `le`, `gt`, and `ge` methods of this trait can be called using +/// the `<`, `<=`, `>`, and `>=` operators, respectively. +/// +/// The methods of this trait must be consistent with each other and with those of `PartialEq` in +/// the following sense: +/// +/// - `a == b` if and only if `partial_cmp(a, b) == Some(Equal)`. +/// - `a < b` if and only if `partial_cmp(a, b) == Some(Less)` +/// (ensured by the default implementation). +/// - `a > b` if and only if `partial_cmp(a, b) == Some(Greater)` +/// (ensured by the default implementation). +/// - `a <= b` if and only if `a < b || a == b` +/// (ensured by the default implementation). +/// - `a >= b` if and only if `a > b || a == b` +/// (ensured by the default implementation). +/// - `a != b` if and only if `!(a == b)` (already part of `PartialEq`). +/// +/// If [`Ord`] is also implemented for `Self` and `Rhs`, it must also be consistent with +/// `partial_cmp` (see the documentation of that trait for the exact requirements). It's +/// easy to accidentally make them disagree by deriving some of the traits and manually +/// implementing others. +/// /// The comparison must satisfy, for all `a`, `b` and `c`: /// -/// - asymmetry: if `a < b` then `!(a > b)`, as well as `a > b` implying `!(a < b)`; and /// - transitivity: `a < b` and `b < c` implies `a < c`. The same must hold for both `==` and `>`. +/// - duality: `a < b` if and only if `b > a`. /// /// Note that these requirements mean that the trait itself must be implemented symmetrically and /// transitively: if `T: PartialOrd<U>` and `U: PartialOrd<V>` then `U: PartialOrd<T>` and `T: /// PartialOrd<V>`. /// +/// ## Corollaries +/// +/// The following corollaries follow from the above requirements: +/// +/// - irreflexivity of `<` and `>`: `!(a < a)`, `!(a > a)` +/// - transitivity of `>`: if `a > b` and `b > c` then `a > c` +/// - duality of `partial_cmp`: `partial_cmp(a, b) == partial_cmp(b, a).map(Ordering::reverse)` +/// /// ## Derivable /// /// This trait can be used with `#[derive]`. When `derive`d on structs, it will produce a @@ -850,10 +893,6 @@ impl PartialOrd for Ordering { /// /// `PartialOrd` requires your type to be [`PartialEq`]. /// -/// Implementations of [`PartialEq`], `PartialOrd`, and [`Ord`] *must* agree with each other. It's -/// easy to accidentally make them disagree by deriving some of the traits and manually -/// implementing others. -/// /// If your type is [`Ord`], you can implement [`partial_cmp`] by using [`cmp`]: /// /// ``` @@ -1065,6 +1104,7 @@ pub macro PartialOrd($item:item) { #[inline] #[must_use] #[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr(not(test), rustc_diagnostic_item = "cmp_min")] pub fn min<T: Ord>(v1: T, v2: T) -> T { v1.min(v2) } @@ -1127,6 +1167,7 @@ pub fn min_by_key<T, F: FnMut(&T) -> K, K: Ord>(v1: T, v2: T, mut f: F) -> T { #[inline] #[must_use] #[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr(not(test), rustc_diagnostic_item = "cmp_max")] pub fn max<T: Ord>(v1: T, v2: T) -> T { v1.max(v2) } diff --git a/library/core/src/convert/mod.rs b/library/core/src/convert/mod.rs index 65af8508a68..1e512af4805 100644 --- a/library/core/src/convert/mod.rs +++ b/library/core/src/convert/mod.rs @@ -152,6 +152,7 @@ pub const fn identity<T>(x: T) -> T { /// is_hello(s); /// ``` #[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr(not(test), rustc_diagnostic_item = "AsRef")] pub trait AsRef<T: ?Sized> { /// Performs the conversion. #[stable(feature = "rust1", since = "1.0.0")] @@ -193,6 +194,7 @@ pub trait AsRef<T: ?Sized> { /// /// [`Box<T>`]: ../../std/boxed/struct.Box.html #[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr(not(test), rustc_diagnostic_item = "AsMut")] pub trait AsMut<T: ?Sized> { /// Performs the conversion. #[stable(feature = "rust1", since = "1.0.0")] diff --git a/library/core/src/convert/num.rs b/library/core/src/convert/num.rs index a522b7da3bd..75ef873abc9 100644 --- a/library/core/src/convert/num.rs +++ b/library/core/src/convert/num.rs @@ -45,7 +45,8 @@ impl_float_to_int!(f64 => u8 u16 u32 u64 u128 usize i8 i16 i32 i64 i128 isize); macro_rules! impl_from { ($Small: ty, $Large: ty, #[$attr:meta], $doc: expr) => { #[$attr] - impl From<$Small> for $Large { + #[rustc_const_unstable(feature = "const_num_from_num", issue = "87852")] + impl const From<$Small> for $Large { // Rustdocs on the impl block show a "[+] show undocumented items" toggle. // Rustdocs on functions do not. #[doc = $doc] @@ -145,7 +146,7 @@ impl_from! { i16, isize, #[stable(feature = "lossless_iusize_conv", since = "1.2 // CHERI proposes 256-bit “capabilities”. Unclear if this would be relevant to usize/isize. // https://www.cl.cam.ac.uk/research/security/ctsrd/pdfs/20171017a-cheri-poster.pdf -// http://www.csl.sri.com/users/neumann/2012resolve-cheri.pdf +// https://www.csl.sri.com/users/neumann/2012resolve-cheri.pdf // Note: integers can only be represented with full precision in a float if // they fit in the significand, which is 24 bits in f32 and 53 bits in f64. @@ -172,7 +173,8 @@ impl_from! { f32, f64, #[stable(feature = "lossless_float_conv", since = "1.6.0" macro_rules! try_from_unbounded { ($source:ty, $($target:ty),*) => {$( #[stable(feature = "try_from", since = "1.34.0")] - impl TryFrom<$source> for $target { + #[rustc_const_unstable(feature = "const_num_from_num", issue = "87852")] + impl const TryFrom<$source> for $target { type Error = TryFromIntError; /// Try to create the target number type from a source @@ -190,7 +192,8 @@ macro_rules! try_from_unbounded { macro_rules! try_from_lower_bounded { ($source:ty, $($target:ty),*) => {$( #[stable(feature = "try_from", since = "1.34.0")] - impl TryFrom<$source> for $target { + #[rustc_const_unstable(feature = "const_num_from_num", issue = "87852")] + impl const TryFrom<$source> for $target { type Error = TryFromIntError; /// Try to create the target number type from a source @@ -212,7 +215,8 @@ macro_rules! try_from_lower_bounded { macro_rules! try_from_upper_bounded { ($source:ty, $($target:ty),*) => {$( #[stable(feature = "try_from", since = "1.34.0")] - impl TryFrom<$source> for $target { + #[rustc_const_unstable(feature = "const_num_from_num", issue = "87852")] + impl const TryFrom<$source> for $target { type Error = TryFromIntError; /// Try to create the target number type from a source @@ -234,7 +238,8 @@ macro_rules! try_from_upper_bounded { macro_rules! try_from_both_bounded { ($source:ty, $($target:ty),*) => {$( #[stable(feature = "try_from", since = "1.34.0")] - impl TryFrom<$source> for $target { + #[rustc_const_unstable(feature = "const_num_from_num", issue = "87852")] + impl const TryFrom<$source> for $target { type Error = TryFromIntError; /// Try to create the target number type from a source diff --git a/library/core/src/default.rs b/library/core/src/default.rs index fd7159d35fa..0ee8cd59ba4 100644 --- a/library/core/src/default.rs +++ b/library/core/src/default.rs @@ -161,7 +161,7 @@ pub fn default<T: Default>() -> T { } /// Derive macro generating an impl of the trait `Default`. -#[rustc_builtin_macro] +#[rustc_builtin_macro(Default, attributes(default))] #[stable(feature = "builtin_macro_prelude", since = "1.38.0")] #[allow_internal_unstable(core_intrinsics)] pub macro Default($item:item) { @@ -171,7 +171,8 @@ pub macro Default($item:item) { macro_rules! default_impl { ($t:ty, $v:expr, $doc:tt) => { #[stable(feature = "rust1", since = "1.0.0")] - impl Default for $t { + #[rustc_const_unstable(feature = "const_default_impls", issue = "87864")] + impl const Default for $t { #[inline] #[doc = $doc] fn default() -> $t { diff --git a/library/core/src/fmt/builders.rs b/library/core/src/fmt/builders.rs index b660788c051..8e7b03d02f1 100644 --- a/library/core/src/fmt/builders.rs +++ b/library/core/src/fmt/builders.rs @@ -23,10 +23,7 @@ impl<'buf, 'state> PadAdapter<'buf, 'state> { slot: &'slot mut Option<Self>, state: &'state mut PadAdapterState, ) -> fmt::Formatter<'slot> { - fmt.wrap_buf(move |buf| { - *slot = Some(PadAdapter { buf, state }); - slot.as_mut().unwrap() - }) + fmt.wrap_buf(move |buf| slot.insert(PadAdapter { buf, state })) } } diff --git a/library/core/src/fmt/float.rs b/library/core/src/fmt/float.rs index ece3cde0015..ba65f0fadbd 100644 --- a/library/core/src/fmt/float.rs +++ b/library/core/src/fmt/float.rs @@ -1,6 +1,7 @@ use crate::fmt::{Debug, Display, Formatter, LowerExp, Result, UpperExp}; use crate::mem::MaybeUninit; use crate::num::flt2dec; +use crate::num::fmt as numfmt; // Don't inline this so callers don't use the stack space this function // requires unless they have to. @@ -15,7 +16,7 @@ where T: flt2dec::DecodableFloat, { let mut buf: [MaybeUninit<u8>; 1024] = MaybeUninit::uninit_array(); // enough for f32 and f64 - let mut parts: [MaybeUninit<flt2dec::Part<'_>>; 4] = MaybeUninit::uninit_array(); + let mut parts: [MaybeUninit<numfmt::Part<'_>>; 4] = MaybeUninit::uninit_array(); let formatted = flt2dec::to_exact_fixed_str( flt2dec::strategy::grisu::format_exact, *num, @@ -41,7 +42,7 @@ where { // enough for f32 and f64 let mut buf: [MaybeUninit<u8>; flt2dec::MAX_SIG_DIGITS] = MaybeUninit::uninit_array(); - let mut parts: [MaybeUninit<flt2dec::Part<'_>>; 4] = MaybeUninit::uninit_array(); + let mut parts: [MaybeUninit<numfmt::Part<'_>>; 4] = MaybeUninit::uninit_array(); let formatted = flt2dec::to_shortest_str( flt2dec::strategy::grisu::format_shortest, *num, @@ -85,7 +86,7 @@ where T: flt2dec::DecodableFloat, { let mut buf: [MaybeUninit<u8>; 1024] = MaybeUninit::uninit_array(); // enough for f32 and f64 - let mut parts: [MaybeUninit<flt2dec::Part<'_>>; 6] = MaybeUninit::uninit_array(); + let mut parts: [MaybeUninit<numfmt::Part<'_>>; 6] = MaybeUninit::uninit_array(); let formatted = flt2dec::to_exact_exp_str( flt2dec::strategy::grisu::format_exact, *num, @@ -112,7 +113,7 @@ where { // enough for f32 and f64 let mut buf: [MaybeUninit<u8>; flt2dec::MAX_SIG_DIGITS] = MaybeUninit::uninit_array(); - let mut parts: [MaybeUninit<flt2dec::Part<'_>>; 6] = MaybeUninit::uninit_array(); + let mut parts: [MaybeUninit<numfmt::Part<'_>>; 6] = MaybeUninit::uninit_array(); let formatted = flt2dec::to_shortest_exp_str( flt2dec::strategy::grisu::format_shortest, *num, diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs index 02ac4fb8006..6ad10990840 100644 --- a/library/core/src/fmt/mod.rs +++ b/library/core/src/fmt/mod.rs @@ -7,13 +7,16 @@ use crate::char::EscapeDebugExtArgs; use crate::iter; use crate::marker::PhantomData; use crate::mem; -use crate::num::flt2dec; +use crate::num::fmt as numfmt; use crate::ops::Deref; use crate::result; use crate::str; mod builders; +#[cfg(not(no_fp_fmt_parse))] mod float; +#[cfg(no_fp_fmt_parse)] +mod nofloat; mod num; #[stable(feature = "fmt_flags_align", since = "1.28.0")] @@ -334,7 +337,8 @@ impl<'a> Arguments<'a> { #[doc(hidden)] #[inline] #[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")] - pub fn new_v1(pieces: &'a [&'static str], args: &'a [ArgumentV1<'a>]) -> Arguments<'a> { + #[rustc_const_unstable(feature = "const_fmt_arguments_new", issue = "none")] + pub const fn new_v1(pieces: &'a [&'static str], args: &'a [ArgumentV1<'a>]) -> Arguments<'a> { Arguments { pieces, fmt: None, args } } @@ -347,7 +351,8 @@ impl<'a> Arguments<'a> { #[doc(hidden)] #[inline] #[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")] - pub fn new_v1_formatted( + #[rustc_const_unstable(feature = "const_fmt_arguments_new", issue = "none")] + pub const fn new_v1_formatted( pieces: &'a [&'static str], args: &'a [ArgumentV1<'a>], fmt: &'a [rt::v1::Argument], @@ -444,8 +449,9 @@ impl<'a> Arguments<'a> { /// assert_eq!(format_args!("{}", 1).as_str(), None); /// ``` #[stable(feature = "fmt_as_str", since = "1.52.0")] + #[rustc_const_unstable(feature = "const_arguments_as_str", issue = "none")] #[inline] - pub fn as_str(&self) -> Option<&'static str> { + pub const fn as_str(&self) -> Option<&'static str> { match (self.pieces, self.args) { ([], []) => Some(""), ([s], []) => Some(s), @@ -564,7 +570,7 @@ impl Display for Arguments<'_> { on( crate_local, label = "`{Self}` cannot be formatted using `{{:?}}`", - note = "add `#[derive(Debug)]` or manually implement `{Debug}`" + note = "add `#[derive(Debug)]` to `{Self}` or manually `impl {Debug} for {Self}`" ), message = "`{Self}` doesn't implement `{Debug}`", label = "`{Self}` cannot be formatted using `{{:?}}` because it doesn't implement `{Debug}`" @@ -662,6 +668,7 @@ pub use macros::Debug; note = "in format strings you may be able to use `{{:?}}` (or {{:#?}} for pretty-print) instead" )] #[doc(alias = "{}")] +#[rustc_diagnostic_item = "display_trait"] #[stable(feature = "rust1", since = "1.0.0")] pub trait Display { /// Formats the value using the given formatter. @@ -1421,7 +1428,7 @@ impl<'a> Formatter<'a> { /// Takes the formatted parts and applies the padding. /// Assumes that the caller already has rendered the parts with required precision, /// so that `self.precision` can be ignored. - fn pad_formatted_parts(&mut self, formatted: &flt2dec::Formatted<'_>) -> Result { + fn pad_formatted_parts(&mut self, formatted: &numfmt::Formatted<'_>) -> Result { if let Some(mut width) = self.width { // for the sign-aware zero padding, we render the sign first and // behave as if we had no sign from the beginning. @@ -1461,14 +1468,14 @@ impl<'a> Formatter<'a> { } } - fn write_formatted_parts(&mut self, formatted: &flt2dec::Formatted<'_>) -> Result { + fn write_formatted_parts(&mut self, formatted: &numfmt::Formatted<'_>) -> Result { fn write_bytes(buf: &mut dyn Write, s: &[u8]) -> Result { - // SAFETY: This is used for `flt2dec::Part::Num` and `flt2dec::Part::Copy`. - // It's safe to use for `flt2dec::Part::Num` since every char `c` is between + // SAFETY: This is used for `numfmt::Part::Num` and `numfmt::Part::Copy`. + // It's safe to use for `numfmt::Part::Num` since every char `c` is between // `b'0'` and `b'9'`, which means `s` is valid UTF-8. - // It's also probably safe in practice to use for `flt2dec::Part::Copy(buf)` + // It's also probably safe in practice to use for `numfmt::Part::Copy(buf)` // since `buf` should be plain ASCII, but it's possible for someone to pass - // in a bad value for `buf` into `flt2dec::to_shortest_str` since it is a + // in a bad value for `buf` into `numfmt::to_shortest_str` since it is a // public function. // FIXME: Determine whether this could result in UB. buf.write_str(unsafe { str::from_utf8_unchecked(s) }) @@ -1479,7 +1486,7 @@ impl<'a> Formatter<'a> { } for part in formatted.parts { match *part { - flt2dec::Part::Zero(mut nzeroes) => { + numfmt::Part::Zero(mut nzeroes) => { const ZEROES: &str = // 64 zeroes "0000000000000000000000000000000000000000000000000000000000000000"; while nzeroes > ZEROES.len() { @@ -1490,7 +1497,7 @@ impl<'a> Formatter<'a> { self.buf.write_str(&ZEROES[..nzeroes])?; } } - flt2dec::Part::Num(mut v) => { + numfmt::Part::Num(mut v) => { let mut s = [0; 5]; let len = part.len(); for c in s[..len].iter_mut().rev() { @@ -1499,7 +1506,7 @@ impl<'a> Formatter<'a> { } write_bytes(self.buf, &s[..len])?; } - flt2dec::Part::Copy(buf) => { + numfmt::Part::Copy(buf) => { write_bytes(self.buf, buf)?; } } diff --git a/library/core/src/fmt/nofloat.rs b/library/core/src/fmt/nofloat.rs new file mode 100644 index 00000000000..cfb94cd9de5 --- /dev/null +++ b/library/core/src/fmt/nofloat.rs @@ -0,0 +1,15 @@ +use crate::fmt::{Debug, Formatter, Result}; + +macro_rules! floating { + ($ty:ident) => { + #[stable(feature = "rust1", since = "1.0.0")] + impl Debug for $ty { + fn fmt(&self, _fmt: &mut Formatter<'_>) -> Result { + panic!("floating point support is turned off"); + } + } + }; +} + +floating! { f32 } +floating! { f64 } diff --git a/library/core/src/fmt/num.rs b/library/core/src/fmt/num.rs index cdd731fdd4d..db45640df48 100644 --- a/library/core/src/fmt/num.rs +++ b/library/core/src/fmt/num.rs @@ -2,7 +2,7 @@ use crate::fmt; use crate::mem::MaybeUninit; -use crate::num::flt2dec; +use crate::num::fmt as numfmt; use crate::ops::{Div, Rem, Sub}; use crate::ptr; use crate::slice; @@ -406,9 +406,9 @@ macro_rules! impl_Exp { }; let parts = &[ - flt2dec::Part::Copy(buf_slice), - flt2dec::Part::Zero(added_precision), - flt2dec::Part::Copy(exp_slice) + numfmt::Part::Copy(buf_slice), + numfmt::Part::Zero(added_precision), + numfmt::Part::Copy(exp_slice) ]; let sign = if !is_nonnegative { "-" @@ -417,7 +417,7 @@ macro_rules! impl_Exp { } else { "" }; - let formatted = flt2dec::Formatted{sign, parts}; + let formatted = numfmt::Formatted{sign, parts}; f.pad_formatted_parts(&formatted) } diff --git a/library/core/src/future/future.rs b/library/core/src/future/future.rs index 15952c6806f..09d8a2aac26 100644 --- a/library/core/src/future/future.rs +++ b/library/core/src/future/future.rs @@ -7,7 +7,7 @@ use crate::task::{Context, Poll}; /// A future represents an asynchronous computation. /// -/// A future is a value that may not have finished computing yet. This kind of +/// A future is a value that might not have finished computing yet. This kind of /// "asynchronous value" makes it possible for a thread to continue doing useful /// work while it waits for the value to become available. /// @@ -111,11 +111,11 @@ impl<F: ?Sized + Future + Unpin> Future for &mut F { #[stable(feature = "futures_api", since = "1.36.0")] impl<P> Future for Pin<P> where - P: Unpin + ops::DerefMut<Target: Future>, + P: ops::DerefMut<Target: Future>, { type Output = <<P as ops::Deref>::Target as Future>::Output; fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { - Pin::get_mut(self).as_mut().poll(cx) + <P::Target as Future>::poll(self.as_deref_mut(), cx) } } diff --git a/library/core/src/future/ready.rs b/library/core/src/future/ready.rs index b0c7fbb1d7a..cc905d288f9 100644 --- a/library/core/src/future/ready.rs +++ b/library/core/src/future/ready.rs @@ -20,7 +20,7 @@ impl<T> Future for Ready<T> { #[inline] fn poll(mut self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<T> { - Poll::Ready(self.0.take().expect("Ready polled after completion")) + Poll::Ready(self.0.take().expect("`Ready` polled after completion")) } } diff --git a/library/core/src/hash/mod.rs b/library/core/src/hash/mod.rs index 77d3a35b268..77161e961e7 100644 --- a/library/core/src/hash/mod.rs +++ b/library/core/src/hash/mod.rs @@ -481,6 +481,53 @@ pub trait BuildHasher { /// ``` #[stable(since = "1.7.0", feature = "build_hasher")] fn build_hasher(&self) -> Self::Hasher; + + /// Calculates the hash of a single value. + /// + /// This is intended as a convenience for code which *consumes* hashes, such + /// as the implementation of a hash table or in unit tests that check + /// whether a custom [`Hash`] implementation behaves as expected. + /// + /// This must not be used in any code which *creates* hashes, such as in an + /// implementation of [`Hash`]. The way to create a combined hash of + /// multiple values is to call [`Hash::hash`] multiple times using the same + /// [`Hasher`], not to call this method repeatedly and combine the results. + /// + /// # Example + /// + /// ``` + /// #![feature(build_hasher_simple_hash_one)] + /// + /// use std::cmp::{max, min}; + /// use std::hash::{BuildHasher, Hash, Hasher}; + /// struct OrderAmbivalentPair<T: Ord>(T, T); + /// impl<T: Ord + Hash> Hash for OrderAmbivalentPair<T> { + /// fn hash<H: Hasher>(&self, hasher: &mut H) { + /// min(&self.0, &self.1).hash(hasher); + /// max(&self.0, &self.1).hash(hasher); + /// } + /// } + /// + /// // Then later, in a `#[test]` for the type... + /// let bh = std::collections::hash_map::RandomState::new(); + /// assert_eq!( + /// bh.hash_one(OrderAmbivalentPair(1, 2)), + /// bh.hash_one(OrderAmbivalentPair(2, 1)) + /// ); + /// assert_eq!( + /// bh.hash_one(OrderAmbivalentPair(10, 2)), + /// bh.hash_one(&OrderAmbivalentPair(2, 10)) + /// ); + /// ``` + #[unstable(feature = "build_hasher_simple_hash_one", issue = "86161")] + fn hash_one<T: Hash>(&self, x: T) -> u64 + where + Self: Sized, + { + let mut hasher = self.build_hasher(); + x.hash(&mut hasher); + hasher.finish() + } } /// Used to create a default [`BuildHasher`] instance for types that implement @@ -555,7 +602,8 @@ impl<H> Clone for BuildHasherDefault<H> { } #[stable(since = "1.7.0", feature = "build_hasher")] -impl<H> Default for BuildHasherDefault<H> { +#[rustc_const_unstable(feature = "const_default_impls", issue = "87864")] +impl<H> const Default for BuildHasherDefault<H> { fn default() -> BuildHasherDefault<H> { BuildHasherDefault(marker::PhantomData) } diff --git a/library/core/src/hint.rs b/library/core/src/hint.rs index a0b65399da2..ba878ff66a0 100644 --- a/library/core/src/hint.rs +++ b/library/core/src/hint.rs @@ -152,23 +152,20 @@ pub fn spin_loop() { /// backend used. Programs cannot rely on `black_box` for *correctness* in any way. /// /// [`std::convert::identity`]: crate::convert::identity -#[cfg_attr(not(miri), inline)] -#[cfg_attr(miri, inline(never))] +#[inline] #[unstable(feature = "bench_black_box", issue = "64102")] -#[cfg_attr(miri, allow(unused_mut))] +#[cfg_attr(not(bootstrap), allow(unused_mut))] +#[cfg_attr(bootstrap, allow(deprecated))] pub fn black_box<T>(mut dummy: T) -> T { - // We need to "use" the argument in some way LLVM can't introspect, and on - // targets that support it we can typically leverage inline assembly to do - // this. LLVM's interpretation of inline assembly is that it's, well, a black - // box. This isn't the greatest implementation since it probably deoptimizes - // more than we want, but it's so far good enough. - - #[cfg(not(miri))] // This is just a hint, so it is fine to skip in Miri. + #[cfg(bootstrap)] // SAFETY: the inline assembly is a no-op. unsafe { - // FIXME: Cannot use `asm!` because it doesn't support MIPS and other architectures. llvm_asm!("" : : "r"(&mut dummy) : "memory" : "volatile"); + dummy } - dummy + #[cfg(not(bootstrap))] + { + crate::intrinsics::black_box(dummy) + } } diff --git a/library/core/src/internal_macros.rs b/library/core/src/internal_macros.rs index 4ea7dfc0735..be12f904640 100644 --- a/library/core/src/internal_macros.rs +++ b/library/core/src/internal_macros.rs @@ -77,7 +77,6 @@ macro_rules! forward_ref_op_assign { } /// Create a zero-size type similar to a closure type, but named. -#[unstable(feature = "std_internals", issue = "none")] macro_rules! impl_fn_for_zst { ($( $( #[$attr: meta] )* diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index 0034de9ad1b..272b1e3a1d7 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -25,7 +25,7 @@ //! across other volatile intrinsics. See the LLVM documentation on //! [[volatile]]. //! -//! [volatile]: http://llvm.org/docs/LangRef.html#volatile-memory-accesses +//! [volatile]: https://llvm.org/docs/LangRef.html#volatile-memory-accesses //! //! # Atomics //! @@ -33,7 +33,7 @@ //! words, with multiple possible memory orderings. They obey the same //! semantics as C++11. See the LLVM documentation on [[atomics]]. //! -//! [atomics]: http://llvm.org/docs/Atomics.html +//! [atomics]: https://llvm.org/docs/Atomics.html //! //! A quick refresher on memory ordering: //! @@ -712,8 +712,19 @@ extern "rust-intrinsic" { /// Aborts the execution of the process. /// - /// A more user-friendly and stable version of this operation is - /// [`std::process::abort`](../../std/process/fn.abort.html). + /// Note that, unlike most intrinsics, this is safe to call; + /// it does not require an `unsafe` block. + /// Therefore, implementations must not require the user to uphold + /// any safety invariants. + /// + /// [`std::process::abort`](../../std/process/fn.abort.html) is to be preferred if possible, + /// as its behavior is more user-friendly and more stable. + /// + /// The current implementation of `intrinsics::abort` is to invoke an invalid instruction, + /// on most platforms. + /// On Unix, the + /// process will probably terminate with a signal like `SIGABRT`, `SIGILL`, `SIGTRAP`, `SIGSEGV` or + /// `SIGBUS`. The precise behaviour is not guaranteed and not stable. pub fn abort() -> !; /// Informs the optimizer that this point in the code is not reachable, @@ -745,6 +756,11 @@ extern "rust-intrinsic" { /// /// Any use other than with `if` statements will probably not have an effect. /// + /// Note that, unlike most intrinsics, this is safe to call; + /// it does not require an `unsafe` block. + /// Therefore, implementations must not require the user to uphold + /// any safety invariants. + /// /// This intrinsic does not have a stable counterpart. #[rustc_const_unstable(feature = "const_likely", issue = "none")] pub fn likely(b: bool) -> bool; @@ -754,6 +770,11 @@ extern "rust-intrinsic" { /// /// Any use other than with `if` statements will probably not have an effect. /// + /// Note that, unlike most intrinsics, this is safe to call; + /// it does not require an `unsafe` block. + /// Therefore, implementations must not require the user to uphold + /// any safety invariants. + /// /// This intrinsic does not have a stable counterpart. #[rustc_const_unstable(feature = "const_likely", issue = "none")] pub fn unlikely(b: bool) -> bool; @@ -765,6 +786,11 @@ extern "rust-intrinsic" { /// The size of a type in bytes. /// + /// Note that, unlike most intrinsics, this is safe to call; + /// it does not require an `unsafe` block. + /// Therefore, implementations must not require the user to uphold + /// any safety invariants. + /// /// More specifically, this is the offset in bytes between successive /// items of the same type, including alignment padding. /// @@ -774,6 +800,11 @@ extern "rust-intrinsic" { /// The minimum alignment of a type. /// + /// Note that, unlike most intrinsics, this is safe to call; + /// it does not require an `unsafe` block. + /// Therefore, implementations must not require the user to uphold + /// any safety invariants. + /// /// The stabilized version of this intrinsic is [`core::mem::align_of`]. #[rustc_const_stable(feature = "const_min_align_of", since = "1.40.0")] pub fn min_align_of<T>() -> usize; @@ -796,6 +827,11 @@ extern "rust-intrinsic" { /// Gets a static string slice containing the name of a type. /// + /// Note that, unlike most intrinsics, this is safe to call; + /// it does not require an `unsafe` block. + /// Therefore, implementations must not require the user to uphold + /// any safety invariants. + /// /// The stabilized version of this intrinsic is [`core::any::type_name`]. #[rustc_const_unstable(feature = "const_type_name", issue = "63084")] pub fn type_name<T: ?Sized>() -> &'static str; @@ -804,6 +840,11 @@ extern "rust-intrinsic" { /// function will return the same value for a type regardless of whichever /// crate it is invoked in. /// + /// Note that, unlike most intrinsics, this is safe to call; + /// it does not require an `unsafe` block. + /// Therefore, implementations must not require the user to uphold + /// any safety invariants. + /// /// The stabilized version of this intrinsic is [`core::any::TypeId::of`]. #[rustc_const_unstable(feature = "const_type_id", issue = "77125")] pub fn type_id<T: ?Sized + 'static>() -> u64; @@ -829,6 +870,11 @@ extern "rust-intrinsic" { /// Gets a reference to a static `Location` indicating where it was called. /// + /// Note that, unlike most intrinsics, this is safe to call; + /// it does not require an `unsafe` block. + /// Therefore, implementations must not require the user to uphold + /// any safety invariants. + /// /// Consider using [`core::panic::Location::caller`] instead. #[rustc_const_unstable(feature = "const_caller_location", issue = "76156")] pub fn caller_location() -> &'static crate::panic::Location<'static>; @@ -837,6 +883,11 @@ extern "rust-intrinsic" { /// /// This exists solely for [`mem::forget_unsized`]; normal `forget` uses /// `ManuallyDrop` instead. + /// + /// Note that, unlike most intrinsics, this is safe to call; + /// it does not require an `unsafe` block. + /// Therefore, implementations must not require the user to uphold + /// any safety invariants. #[rustc_const_unstable(feature = "const_intrinsic_forget", issue = "none")] pub fn forget<T: ?Sized>(_: T); @@ -860,6 +911,9 @@ extern "rust-intrinsic" { /// cause [undefined behavior][ub] with this function. `transmute` should be /// the absolute last resort. /// + /// Transmuting pointers to integers in a `const` context is [undefined behavior][ub]. + /// Any attempt to use the resulting value for integer operations will abort const-evaluation. + /// /// The [nomicon](../../nomicon/transmutes.html) has additional /// documentation. /// @@ -1077,8 +1131,6 @@ extern "rust-intrinsic" { /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] - // NOTE: While this makes the intrinsic const stable, we have some custom code in const fn - // checks that prevent its use within `const fn`. #[rustc_const_stable(feature = "const_transmute", since = "1.46.0")] #[rustc_diagnostic_item = "transmute"] pub fn transmute<T, U>(e: T) -> U; @@ -1090,6 +1142,11 @@ extern "rust-intrinsic" { /// If the actual type neither requires drop glue nor implements /// `Copy`, then the return value of this function is unspecified. /// + /// Note that, unlike most intrinsics, this is safe to call; + /// it does not require an `unsafe` block. + /// Therefore, implementations must not require the user to uphold + /// any safety invariants. + /// /// The stabilized version of this intrinsic is [`mem::needs_drop`](crate::mem::needs_drop). #[rustc_const_stable(feature = "const_needs_drop", since = "1.40.0")] pub fn needs_drop<T>() -> bool; @@ -1310,21 +1367,41 @@ extern "rust-intrinsic" { /// Returns the minimum of two `f32` values. /// + /// Note that, unlike most intrinsics, this is safe to call; + /// it does not require an `unsafe` block. + /// Therefore, implementations must not require the user to uphold + /// any safety invariants. + /// /// The stabilized version of this intrinsic is /// [`f32::min`] pub fn minnumf32(x: f32, y: f32) -> f32; /// Returns the minimum of two `f64` values. /// + /// Note that, unlike most intrinsics, this is safe to call; + /// it does not require an `unsafe` block. + /// Therefore, implementations must not require the user to uphold + /// any safety invariants. + /// /// The stabilized version of this intrinsic is /// [`f64::min`] pub fn minnumf64(x: f64, y: f64) -> f64; /// Returns the maximum of two `f32` values. /// + /// Note that, unlike most intrinsics, this is safe to call; + /// it does not require an `unsafe` block. + /// Therefore, implementations must not require the user to uphold + /// any safety invariants. + /// /// The stabilized version of this intrinsic is /// [`f32::max`] pub fn maxnumf32(x: f32, y: f32) -> f32; /// Returns the maximum of two `f64` values. /// + /// Note that, unlike most intrinsics, this is safe to call; + /// it does not require an `unsafe` block. + /// Therefore, implementations must not require the user to uphold + /// any safety invariants. + /// /// The stabilized version of this intrinsic is /// [`f64::max`] pub fn maxnumf64(x: f64, y: f64) -> f64; @@ -1438,6 +1515,11 @@ extern "rust-intrinsic" { /// Returns the number of bits set in an integer type `T` /// + /// Note that, unlike most intrinsics, this is safe to call; + /// it does not require an `unsafe` block. + /// Therefore, implementations must not require the user to uphold + /// any safety invariants. + /// /// The stabilized versions of this intrinsic are available on the integer /// primitives via the `count_ones` method. For example, /// [`u32::count_ones`] @@ -1446,6 +1528,11 @@ extern "rust-intrinsic" { /// Returns the number of leading unset bits (zeroes) in an integer type `T`. /// + /// Note that, unlike most intrinsics, this is safe to call; + /// it does not require an `unsafe` block. + /// Therefore, implementations must not require the user to uphold + /// any safety invariants. + /// /// The stabilized versions of this intrinsic are available on the integer /// primitives via the `leading_zeros` method. For example, /// [`u32::leading_zeros`] @@ -1497,6 +1584,11 @@ extern "rust-intrinsic" { /// Returns the number of trailing unset bits (zeroes) in an integer type `T`. /// + /// Note that, unlike most intrinsics, this is safe to call; + /// it does not require an `unsafe` block. + /// Therefore, implementations must not require the user to uphold + /// any safety invariants. + /// /// The stabilized versions of this intrinsic are available on the integer /// primitives via the `trailing_zeros` method. For example, /// [`u32::trailing_zeros`] @@ -1548,6 +1640,11 @@ extern "rust-intrinsic" { /// Reverses the bytes in an integer type `T`. /// + /// Note that, unlike most intrinsics, this is safe to call; + /// it does not require an `unsafe` block. + /// Therefore, implementations must not require the user to uphold + /// any safety invariants. + /// /// The stabilized versions of this intrinsic are available on the integer /// primitives via the `swap_bytes` method. For example, /// [`u32::swap_bytes`] @@ -1556,6 +1653,11 @@ extern "rust-intrinsic" { /// Reverses the bits in an integer type `T`. /// + /// Note that, unlike most intrinsics, this is safe to call; + /// it does not require an `unsafe` block. + /// Therefore, implementations must not require the user to uphold + /// any safety invariants. + /// /// The stabilized versions of this intrinsic are available on the integer /// primitives via the `reverse_bits` method. For example, /// [`u32::reverse_bits`] @@ -1564,6 +1666,11 @@ extern "rust-intrinsic" { /// Performs checked integer addition. /// + /// Note that, unlike most intrinsics, this is safe to call; + /// it does not require an `unsafe` block. + /// Therefore, implementations must not require the user to uphold + /// any safety invariants. + /// /// The stabilized versions of this intrinsic are available on the integer /// primitives via the `overflowing_add` method. For example, /// [`u32::overflowing_add`] @@ -1572,6 +1679,11 @@ extern "rust-intrinsic" { /// Performs checked integer subtraction /// + /// Note that, unlike most intrinsics, this is safe to call; + /// it does not require an `unsafe` block. + /// Therefore, implementations must not require the user to uphold + /// any safety invariants. + /// /// The stabilized versions of this intrinsic are available on the integer /// primitives via the `overflowing_sub` method. For example, /// [`u32::overflowing_sub`] @@ -1580,6 +1692,11 @@ extern "rust-intrinsic" { /// Performs checked integer multiplication /// + /// Note that, unlike most intrinsics, this is safe to call; + /// it does not require an `unsafe` block. + /// Therefore, implementations must not require the user to uphold + /// any safety invariants. + /// /// The stabilized versions of this intrinsic are available on the integer /// primitives via the `overflowing_mul` method. For example, /// [`u32::overflowing_mul`] @@ -1649,6 +1766,11 @@ extern "rust-intrinsic" { /// Performs rotate left. /// + /// Note that, unlike most intrinsics, this is safe to call; + /// it does not require an `unsafe` block. + /// Therefore, implementations must not require the user to uphold + /// any safety invariants. + /// /// The stabilized versions of this intrinsic are available on the integer /// primitives via the `rotate_left` method. For example, /// [`u32::rotate_left`] @@ -1657,6 +1779,11 @@ extern "rust-intrinsic" { /// Performs rotate right. /// + /// Note that, unlike most intrinsics, this is safe to call; + /// it does not require an `unsafe` block. + /// Therefore, implementations must not require the user to uphold + /// any safety invariants. + /// /// The stabilized versions of this intrinsic are available on the integer /// primitives via the `rotate_right` method. For example, /// [`u32::rotate_right`] @@ -1665,6 +1792,11 @@ extern "rust-intrinsic" { /// Returns (a + b) mod 2<sup>N</sup>, where N is the width of T in bits. /// + /// Note that, unlike most intrinsics, this is safe to call; + /// it does not require an `unsafe` block. + /// Therefore, implementations must not require the user to uphold + /// any safety invariants. + /// /// The stabilized versions of this intrinsic are available on the integer /// primitives via the `wrapping_add` method. For example, /// [`u32::wrapping_add`] @@ -1672,6 +1804,11 @@ extern "rust-intrinsic" { pub fn wrapping_add<T: Copy>(a: T, b: T) -> T; /// Returns (a - b) mod 2<sup>N</sup>, where N is the width of T in bits. /// + /// Note that, unlike most intrinsics, this is safe to call; + /// it does not require an `unsafe` block. + /// Therefore, implementations must not require the user to uphold + /// any safety invariants. + /// /// The stabilized versions of this intrinsic are available on the integer /// primitives via the `wrapping_sub` method. For example, /// [`u32::wrapping_sub`] @@ -1679,6 +1816,11 @@ extern "rust-intrinsic" { pub fn wrapping_sub<T: Copy>(a: T, b: T) -> T; /// Returns (a * b) mod 2<sup>N</sup>, where N is the width of T in bits. /// + /// Note that, unlike most intrinsics, this is safe to call; + /// it does not require an `unsafe` block. + /// Therefore, implementations must not require the user to uphold + /// any safety invariants. + /// /// The stabilized versions of this intrinsic are available on the integer /// primitives via the `wrapping_mul` method. For example, /// [`u32::wrapping_mul`] @@ -1687,6 +1829,11 @@ extern "rust-intrinsic" { /// Computes `a + b`, saturating at numeric bounds. /// + /// Note that, unlike most intrinsics, this is safe to call; + /// it does not require an `unsafe` block. + /// Therefore, implementations must not require the user to uphold + /// any safety invariants. + /// /// The stabilized versions of this intrinsic are available on the integer /// primitives via the `saturating_add` method. For example, /// [`u32::saturating_add`] @@ -1694,6 +1841,11 @@ extern "rust-intrinsic" { pub fn saturating_add<T: Copy>(a: T, b: T) -> T; /// Computes `a - b`, saturating at numeric bounds. /// + /// Note that, unlike most intrinsics, this is safe to call; + /// it does not require an `unsafe` block. + /// Therefore, implementations must not require the user to uphold + /// any safety invariants. + /// /// The stabilized versions of this intrinsic are available on the integer /// primitives via the `saturating_sub` method. For example, /// [`u32::saturating_sub`] @@ -1703,6 +1855,11 @@ extern "rust-intrinsic" { /// Returns the value of the discriminant for the variant in 'v'; /// if `T` has no discriminant, returns `0`. /// + /// Note that, unlike most intrinsics, this is safe to call; + /// it does not require an `unsafe` block. + /// Therefore, implementations must not require the user to uphold + /// any safety invariants. + /// /// The stabilized version of this intrinsic is [`core::mem::discriminant`]. #[rustc_const_unstable(feature = "const_discriminant", issue = "69821")] pub fn discriminant_value<T>(v: &T) -> <T as DiscriminantKind>::Discriminant; @@ -1710,6 +1867,11 @@ extern "rust-intrinsic" { /// Returns the number of variants of the type `T` cast to a `usize`; /// if `T` has no variants, returns `0`. Uninhabited variants will be counted. /// + /// Note that, unlike most intrinsics, this is safe to call; + /// it does not require an `unsafe` block. + /// Therefore, implementations must not require the user to uphold + /// any safety invariants. + /// /// The to-be-stabilized version of this intrinsic is [`mem::variant_count`]. #[rustc_const_unstable(feature = "variant_count", issue = "73662")] pub fn variant_count<T>() -> usize; @@ -1732,10 +1894,20 @@ extern "rust-intrinsic" { pub fn ptr_offset_from<T>(ptr: *const T, base: *const T) -> isize; /// See documentation of `<*const T>::guaranteed_eq` for details. + /// + /// Note that, unlike most intrinsics, this is safe to call; + /// it does not require an `unsafe` block. + /// Therefore, implementations must not require the user to uphold + /// any safety invariants. #[rustc_const_unstable(feature = "const_raw_ptr_comparison", issue = "53020")] pub fn ptr_guaranteed_eq<T>(ptr: *const T, other: *const T) -> bool; /// See documentation of `<*const T>::guaranteed_ne` for details. + /// + /// Note that, unlike most intrinsics, this is safe to call; + /// it does not require an `unsafe` block. + /// Therefore, implementations must not require the user to uphold + /// any safety invariants. #[rustc_const_unstable(feature = "const_raw_ptr_comparison", issue = "53020")] pub fn ptr_guaranteed_ne<T>(ptr: *const T, other: *const T) -> bool; @@ -1743,156 +1915,30 @@ extern "rust-intrinsic" { #[rustc_const_unstable(feature = "const_heap", issue = "79597")] pub fn const_allocate(size: usize, align: usize) -> *mut u8; - /// Copies `count * size_of::<T>()` bytes from `src` to `dst`. The source - /// and destination must *not* overlap. + /// Determines whether the raw bytes of the two values are equal. /// - /// For regions of memory which might overlap, use [`copy`] instead. + /// The is particularly handy for arrays, since it allows things like just + /// comparing `i96`s instead of forcing `alloca`s for `[6 x i16]`. /// - /// `copy_nonoverlapping` is semantically equivalent to C's [`memcpy`], but - /// with the argument order swapped. - /// - /// [`memcpy`]: https://en.cppreference.com/w/c/string/byte/memcpy + /// Above some backend-decided threshold this will emit calls to `memcmp`, + /// like slice equality does, instead of causing massive code size. /// /// # Safety /// - /// Behavior is undefined if any of the following conditions are violated: - /// - /// * `src` must be [valid] for reads of `count * size_of::<T>()` bytes. - /// - /// * `dst` must be [valid] for writes of `count * size_of::<T>()` bytes. - /// - /// * Both `src` and `dst` must be properly aligned. + /// It's UB to call this if any of the *bytes* in `*a` or `*b` are uninitialized. + /// Note that this is a stricter criterion than just the *values* being + /// fully-initialized: if `T` has padding, it's UB to call this intrinsic. /// - /// * The region of memory beginning at `src` with a size of `count * - /// size_of::<T>()` bytes must *not* overlap with the region of memory - /// beginning at `dst` with the same size. - /// - /// Like [`read`], `copy_nonoverlapping` creates a bitwise copy of `T`, regardless of - /// whether `T` is [`Copy`]. If `T` is not [`Copy`], using *both* the values - /// in the region beginning at `*src` and the region beginning at `*dst` can - /// [violate memory safety][read-ownership]. - /// - /// Note that even if the effectively copied size (`count * size_of::<T>()`) is - /// `0`, the pointers must be non-null and properly aligned. - /// - /// [`read`]: crate::ptr::read - /// [read-ownership]: crate::ptr::read#ownership-of-the-returned-value - /// [valid]: crate::ptr#safety - /// - /// # Examples - /// - /// Manually implement [`Vec::append`]: - /// - /// ``` - /// use std::ptr; - /// - /// /// Moves all the elements of `src` into `dst`, leaving `src` empty. - /// fn append<T>(dst: &mut Vec<T>, src: &mut Vec<T>) { - /// let src_len = src.len(); - /// let dst_len = dst.len(); - /// - /// // Ensure that `dst` has enough capacity to hold all of `src`. - /// dst.reserve(src_len); - /// - /// unsafe { - /// // The call to offset is always safe because `Vec` will never - /// // allocate more than `isize::MAX` bytes. - /// let dst_ptr = dst.as_mut_ptr().offset(dst_len as isize); - /// let src_ptr = src.as_ptr(); - /// - /// // Truncate `src` without dropping its contents. We do this first, - /// // to avoid problems in case something further down panics. - /// src.set_len(0); - /// - /// // The two regions cannot overlap because mutable references do - /// // not alias, and two different vectors cannot own the same - /// // memory. - /// ptr::copy_nonoverlapping(src_ptr, dst_ptr, src_len); - /// - /// // Notify `dst` that it now holds the contents of `src`. - /// dst.set_len(dst_len + src_len); - /// } - /// } - /// - /// let mut a = vec!['r']; - /// let mut b = vec!['u', 's', 't']; - /// - /// append(&mut a, &mut b); - /// - /// assert_eq!(a, &['r', 'u', 's', 't']); - /// assert!(b.is_empty()); - /// ``` - /// - /// [`Vec::append`]: ../../std/vec/struct.Vec.html#method.append - #[doc(alias = "memcpy")] - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")] - pub fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize); + /// (The implementation is allowed to branch on the results of comparisons, + /// which is UB if any of their inputs are `undef`.) + #[rustc_const_unstable(feature = "const_intrinsic_raw_eq", issue = "none")] + pub fn raw_eq<T>(a: &T, b: &T) -> bool; - /// Copies `count * size_of::<T>()` bytes from `src` to `dst`. The source - /// and destination may overlap. + /// See documentation of [`std::hint::black_box`] for details. /// - /// If the source and destination will *never* overlap, - /// [`copy_nonoverlapping`] can be used instead. - /// - /// `copy` is semantically equivalent to C's [`memmove`], but with the argument - /// order swapped. Copying takes place as if the bytes were copied from `src` - /// to a temporary array and then copied from the array to `dst`. - /// - /// [`memmove`]: https://en.cppreference.com/w/c/string/byte/memmove - /// - /// # Safety - /// - /// Behavior is undefined if any of the following conditions are violated: - /// - /// * `src` must be [valid] for reads of `count * size_of::<T>()` bytes. - /// - /// * `dst` must be [valid] for writes of `count * size_of::<T>()` bytes. - /// - /// * Both `src` and `dst` must be properly aligned. - /// - /// Like [`read`], `copy` creates a bitwise copy of `T`, regardless of - /// whether `T` is [`Copy`]. If `T` is not [`Copy`], using both the values - /// in the region beginning at `*src` and the region beginning at `*dst` can - /// [violate memory safety][read-ownership]. - /// - /// Note that even if the effectively copied size (`count * size_of::<T>()`) is - /// `0`, the pointers must be non-null and properly aligned. - /// - /// [`read`]: crate::ptr::read - /// [read-ownership]: crate::ptr::read#ownership-of-the-returned-value - /// [valid]: crate::ptr#safety - /// - /// # Examples - /// - /// Efficiently create a Rust vector from an unsafe buffer: - /// - /// ``` - /// use std::ptr; - /// - /// /// # Safety - /// /// - /// /// * `ptr` must be correctly aligned for its type and non-zero. - /// /// * `ptr` must be valid for reads of `elts` contiguous elements of type `T`. - /// /// * Those elements must not be used after calling this function unless `T: Copy`. - /// # #[allow(dead_code)] - /// unsafe fn from_buf_raw<T>(ptr: *const T, elts: usize) -> Vec<T> { - /// let mut dst = Vec::with_capacity(elts); - /// - /// // SAFETY: Our precondition ensures the source is aligned and valid, - /// // and `Vec::with_capacity` ensures that we have usable space to write them. - /// ptr::copy(ptr, dst.as_mut_ptr(), elts); - /// - /// // SAFETY: We created it with this much capacity earlier, - /// // and the previous `copy` has initialized these elements. - /// dst.set_len(elts); - /// dst - /// } - /// ``` - #[doc(alias = "memmove")] - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")] - pub fn copy<T>(src: *const T, dst: *mut T, count: usize); + /// [`std::hint::black_box`]: crate::hint::black_box + #[cfg(not(bootstrap))] + pub fn black_box<T>(dummy: T) -> T; } // Some functions are defined here because they accidentally got made @@ -1906,6 +1952,192 @@ pub(crate) fn is_aligned_and_not_null<T>(ptr: *const T) -> bool { !ptr.is_null() && ptr as usize % mem::align_of::<T>() == 0 } +/// Copies `count * size_of::<T>()` bytes from `src` to `dst`. The source +/// and destination must *not* overlap. +/// +/// For regions of memory which might overlap, use [`copy`] instead. +/// +/// `copy_nonoverlapping` is semantically equivalent to C's [`memcpy`], but +/// with the argument order swapped. +/// +/// [`memcpy`]: https://en.cppreference.com/w/c/string/byte/memcpy +/// +/// # Safety +/// +/// Behavior is undefined if any of the following conditions are violated: +/// +/// * `src` must be [valid] for reads of `count * size_of::<T>()` bytes. +/// +/// * `dst` must be [valid] for writes of `count * size_of::<T>()` bytes. +/// +/// * Both `src` and `dst` must be properly aligned. +/// +/// * The region of memory beginning at `src` with a size of `count * +/// size_of::<T>()` bytes must *not* overlap with the region of memory +/// beginning at `dst` with the same size. +/// +/// Like [`read`], `copy_nonoverlapping` creates a bitwise copy of `T`, regardless of +/// whether `T` is [`Copy`]. If `T` is not [`Copy`], using *both* the values +/// in the region beginning at `*src` and the region beginning at `*dst` can +/// [violate memory safety][read-ownership]. +/// +/// Note that even if the effectively copied size (`count * size_of::<T>()`) is +/// `0`, the pointers must be non-null and properly aligned. +/// +/// [`read`]: crate::ptr::read +/// [read-ownership]: crate::ptr::read#ownership-of-the-returned-value +/// [valid]: crate::ptr#safety +/// +/// # Examples +/// +/// Manually implement [`Vec::append`]: +/// +/// ``` +/// use std::ptr; +/// +/// /// Moves all the elements of `src` into `dst`, leaving `src` empty. +/// fn append<T>(dst: &mut Vec<T>, src: &mut Vec<T>) { +/// let src_len = src.len(); +/// let dst_len = dst.len(); +/// +/// // Ensure that `dst` has enough capacity to hold all of `src`. +/// dst.reserve(src_len); +/// +/// unsafe { +/// // The call to offset is always safe because `Vec` will never +/// // allocate more than `isize::MAX` bytes. +/// let dst_ptr = dst.as_mut_ptr().offset(dst_len as isize); +/// let src_ptr = src.as_ptr(); +/// +/// // Truncate `src` without dropping its contents. We do this first, +/// // to avoid problems in case something further down panics. +/// src.set_len(0); +/// +/// // The two regions cannot overlap because mutable references do +/// // not alias, and two different vectors cannot own the same +/// // memory. +/// ptr::copy_nonoverlapping(src_ptr, dst_ptr, src_len); +/// +/// // Notify `dst` that it now holds the contents of `src`. +/// dst.set_len(dst_len + src_len); +/// } +/// } +/// +/// let mut a = vec!['r']; +/// let mut b = vec!['u', 's', 't']; +/// +/// append(&mut a, &mut b); +/// +/// assert_eq!(a, &['r', 'u', 's', 't']); +/// assert!(b.is_empty()); +/// ``` +/// +/// [`Vec::append`]: ../../std/vec/struct.Vec.html#method.append +#[doc(alias = "memcpy")] +#[stable(feature = "rust1", since = "1.0.0")] +#[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")] +#[inline] +pub const unsafe fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize) { + extern "rust-intrinsic" { + #[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")] + pub fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize); + } + + // FIXME: Perform these checks only at run time + /*if cfg!(debug_assertions) + && !(is_aligned_and_not_null(src) + && is_aligned_and_not_null(dst) + && is_nonoverlapping(src, dst, count)) + { + // Not panicking to keep codegen impact smaller. + abort(); + }*/ + + // SAFETY: the safety contract for `copy_nonoverlapping` must be + // upheld by the caller. + unsafe { copy_nonoverlapping(src, dst, count) } +} + +/// Copies `count * size_of::<T>()` bytes from `src` to `dst`. The source +/// and destination may overlap. +/// +/// If the source and destination will *never* overlap, +/// [`copy_nonoverlapping`] can be used instead. +/// +/// `copy` is semantically equivalent to C's [`memmove`], but with the argument +/// order swapped. Copying takes place as if the bytes were copied from `src` +/// to a temporary array and then copied from the array to `dst`. +/// +/// [`memmove`]: https://en.cppreference.com/w/c/string/byte/memmove +/// +/// # Safety +/// +/// Behavior is undefined if any of the following conditions are violated: +/// +/// * `src` must be [valid] for reads of `count * size_of::<T>()` bytes. +/// +/// * `dst` must be [valid] for writes of `count * size_of::<T>()` bytes. +/// +/// * Both `src` and `dst` must be properly aligned. +/// +/// Like [`read`], `copy` creates a bitwise copy of `T`, regardless of +/// whether `T` is [`Copy`]. If `T` is not [`Copy`], using both the values +/// in the region beginning at `*src` and the region beginning at `*dst` can +/// [violate memory safety][read-ownership]. +/// +/// Note that even if the effectively copied size (`count * size_of::<T>()`) is +/// `0`, the pointers must be non-null and properly aligned. +/// +/// [`read`]: crate::ptr::read +/// [read-ownership]: crate::ptr::read#ownership-of-the-returned-value +/// [valid]: crate::ptr#safety +/// +/// # Examples +/// +/// Efficiently create a Rust vector from an unsafe buffer: +/// +/// ``` +/// use std::ptr; +/// +/// /// # Safety +/// /// +/// /// * `ptr` must be correctly aligned for its type and non-zero. +/// /// * `ptr` must be valid for reads of `elts` contiguous elements of type `T`. +/// /// * Those elements must not be used after calling this function unless `T: Copy`. +/// # #[allow(dead_code)] +/// unsafe fn from_buf_raw<T>(ptr: *const T, elts: usize) -> Vec<T> { +/// let mut dst = Vec::with_capacity(elts); +/// +/// // SAFETY: Our precondition ensures the source is aligned and valid, +/// // and `Vec::with_capacity` ensures that we have usable space to write them. +/// ptr::copy(ptr, dst.as_mut_ptr(), elts); +/// +/// // SAFETY: We created it with this much capacity earlier, +/// // and the previous `copy` has initialized these elements. +/// dst.set_len(elts); +/// dst +/// } +/// ``` +#[doc(alias = "memmove")] +#[stable(feature = "rust1", since = "1.0.0")] +#[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")] +#[inline] +pub const unsafe fn copy<T>(src: *const T, dst: *mut T, count: usize) { + extern "rust-intrinsic" { + #[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")] + fn copy<T>(src: *const T, dst: *mut T, count: usize); + } + + // FIXME: Perform these checks only at run time + /*if cfg!(debug_assertions) && !(is_aligned_and_not_null(src) && is_aligned_and_not_null(dst)) { + // Not panicking to keep codegen impact smaller. + abort(); + }*/ + + // SAFETY: the safety contract for `copy` must be upheld by the caller. + unsafe { copy(src, dst, count) } +} + /// Sets `count * size_of::<T>()` bytes of memory starting at `dst` to /// `val`. /// diff --git a/library/core/src/iter/adapters/cloned.rs b/library/core/src/iter/adapters/cloned.rs index 7efc155175c..71a5a4ea831 100644 --- a/library/core/src/iter/adapters/cloned.rs +++ b/library/core/src/iter/adapters/cloned.rs @@ -1,4 +1,6 @@ -use crate::iter::adapters::{zip::try_get_unchecked, TrustedRandomAccess}; +use crate::iter::adapters::{ + zip::try_get_unchecked, TrustedRandomAccess, TrustedRandomAccessNoCoerce, +}; use crate::iter::{FusedIterator, TrustedLen}; use crate::ops::Try; @@ -58,9 +60,10 @@ where self.it.map(T::clone).fold(init, f) } + #[doc(hidden)] unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> T where - Self: TrustedRandomAccess, + Self: TrustedRandomAccessNoCoerce, { // SAFETY: the caller must uphold the contract for // `Iterator::__iterator_get_unchecked`. @@ -120,9 +123,13 @@ where #[doc(hidden)] #[unstable(feature = "trusted_random_access", issue = "none")] -unsafe impl<I> TrustedRandomAccess for Cloned<I> +unsafe impl<I> TrustedRandomAccess for Cloned<I> where I: TrustedRandomAccess {} + +#[doc(hidden)] +#[unstable(feature = "trusted_random_access", issue = "none")] +unsafe impl<I> TrustedRandomAccessNoCoerce for Cloned<I> where - I: TrustedRandomAccess, + I: TrustedRandomAccessNoCoerce, { const MAY_HAVE_SIDE_EFFECT: bool = true; } diff --git a/library/core/src/iter/adapters/copied.rs b/library/core/src/iter/adapters/copied.rs index def24089275..3d3c8da678b 100644 --- a/library/core/src/iter/adapters/copied.rs +++ b/library/core/src/iter/adapters/copied.rs @@ -1,4 +1,6 @@ -use crate::iter::adapters::{zip::try_get_unchecked, TrustedRandomAccess}; +use crate::iter::adapters::{ + zip::try_get_unchecked, TrustedRandomAccess, TrustedRandomAccessNoCoerce, +}; use crate::iter::{FusedIterator, TrustedLen}; use crate::ops::Try; @@ -74,9 +76,10 @@ where self.it.count() } + #[doc(hidden)] unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> T where - Self: TrustedRandomAccess, + Self: TrustedRandomAccessNoCoerce, { // SAFETY: the caller must uphold the contract for // `Iterator::__iterator_get_unchecked`. @@ -136,9 +139,13 @@ where #[doc(hidden)] #[unstable(feature = "trusted_random_access", issue = "none")] -unsafe impl<I> TrustedRandomAccess for Copied<I> +unsafe impl<I> TrustedRandomAccess for Copied<I> where I: TrustedRandomAccess {} + +#[doc(hidden)] +#[unstable(feature = "trusted_random_access", issue = "none")] +unsafe impl<I> TrustedRandomAccessNoCoerce for Copied<I> where - I: TrustedRandomAccess, + I: TrustedRandomAccessNoCoerce, { const MAY_HAVE_SIDE_EFFECT: bool = I::MAY_HAVE_SIDE_EFFECT; } diff --git a/library/core/src/iter/adapters/enumerate.rs b/library/core/src/iter/adapters/enumerate.rs index 91722a4b62a..3478a0cd408 100644 --- a/library/core/src/iter/adapters/enumerate.rs +++ b/library/core/src/iter/adapters/enumerate.rs @@ -1,4 +1,6 @@ -use crate::iter::adapters::{zip::try_get_unchecked, SourceIter, TrustedRandomAccess}; +use crate::iter::adapters::{ + zip::try_get_unchecked, SourceIter, TrustedRandomAccess, TrustedRandomAccessNoCoerce, +}; use crate::iter::{FusedIterator, InPlaceIterable, TrustedLen}; use crate::ops::Try; @@ -111,9 +113,10 @@ where } #[rustc_inherit_overflow_checks] + #[doc(hidden)] unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> <Self as Iterator>::Item where - Self: TrustedRandomAccess, + Self: TrustedRandomAccessNoCoerce, { // SAFETY: the caller must uphold the contract for // `Iterator::__iterator_get_unchecked`. @@ -206,9 +209,13 @@ where #[doc(hidden)] #[unstable(feature = "trusted_random_access", issue = "none")] -unsafe impl<I> TrustedRandomAccess for Enumerate<I> +unsafe impl<I> TrustedRandomAccess for Enumerate<I> where I: TrustedRandomAccess {} + +#[doc(hidden)] +#[unstable(feature = "trusted_random_access", issue = "none")] +unsafe impl<I> TrustedRandomAccessNoCoerce for Enumerate<I> where - I: TrustedRandomAccess, + I: TrustedRandomAccessNoCoerce, { const MAY_HAVE_SIDE_EFFECT: bool = I::MAY_HAVE_SIDE_EFFECT; } diff --git a/library/core/src/iter/adapters/flatten.rs b/library/core/src/iter/adapters/flatten.rs index 3315d346596..48880a4d91a 100644 --- a/library/core/src/iter/adapters/flatten.rs +++ b/library/core/src/iter/adapters/flatten.rs @@ -1,5 +1,5 @@ use crate::fmt; -use crate::iter::{DoubleEndedIterator, Fuse, FusedIterator, Iterator, Map}; +use crate::iter::{DoubleEndedIterator, Fuse, FusedIterator, Iterator, Map, TrustedLen}; use crate::ops::Try; /// An iterator that maps each element to an iterator, and yields the elements @@ -114,6 +114,30 @@ where { } +#[unstable(feature = "trusted_len", issue = "37572")] +unsafe impl<T, I, F, const N: usize> TrustedLen for FlatMap<I, [T; N], F> +where + I: TrustedLen, + F: FnMut(I::Item) -> [T; N], +{ +} + +#[unstable(feature = "trusted_len", issue = "37572")] +unsafe impl<'a, T, I, F, const N: usize> TrustedLen for FlatMap<I, &'a [T; N], F> +where + I: TrustedLen, + F: FnMut(I::Item) -> &'a [T; N], +{ +} + +#[unstable(feature = "trusted_len", issue = "37572")] +unsafe impl<'a, T, I, F, const N: usize> TrustedLen for FlatMap<I, &'a mut [T; N], F> +where + I: TrustedLen, + F: FnMut(I::Item) -> &'a mut [T; N], +{ +} + /// An iterator that flattens one level of nesting in an iterator of things /// that can be turned into iterators. /// @@ -230,6 +254,14 @@ where { } +#[unstable(feature = "trusted_len", issue = "37572")] +unsafe impl<I> TrustedLen for Flatten<I> +where + I: TrustedLen, + <I as Iterator>::Item: TrustedConstSize, +{ +} + /// Real logic of both `Flatten` and `FlatMap` which simply delegate to /// this type. #[derive(Clone, Debug)] @@ -282,6 +314,17 @@ where let (flo, fhi) = self.frontiter.as_ref().map_or((0, Some(0)), U::size_hint); let (blo, bhi) = self.backiter.as_ref().map_or((0, Some(0)), U::size_hint); let lo = flo.saturating_add(blo); + + if let Some(fixed_size) = <<I as Iterator>::Item as ConstSizeIntoIterator>::size() { + let (lower, upper) = self.iter.size_hint(); + + let lower = lower.saturating_mul(fixed_size).saturating_add(lo); + let upper = + try { fhi?.checked_add(bhi?)?.checked_add(fixed_size.checked_mul(upper?)?)? }; + + return (lower, upper); + } + match (self.iter.size_hint(), fhi, bhi) { ((0, Some(0)), Some(a), Some(b)) => (lo, a.checked_add(b)), _ => (lo, None), @@ -444,3 +487,52 @@ where init } } + +trait ConstSizeIntoIterator: IntoIterator { + // FIXME(#31844): convert to an associated const once specialization supports that + fn size() -> Option<usize>; +} + +impl<T> ConstSizeIntoIterator for T +where + T: IntoIterator, +{ + #[inline] + default fn size() -> Option<usize> { + None + } +} + +impl<T, const N: usize> ConstSizeIntoIterator for [T; N] { + #[inline] + fn size() -> Option<usize> { + Some(N) + } +} + +impl<T, const N: usize> ConstSizeIntoIterator for &[T; N] { + #[inline] + fn size() -> Option<usize> { + Some(N) + } +} + +impl<T, const N: usize> ConstSizeIntoIterator for &mut [T; N] { + #[inline] + fn size() -> Option<usize> { + Some(N) + } +} + +#[doc(hidden)] +#[unstable(feature = "std_internals", issue = "none")] +// FIXME(#20400): Instead of this helper trait there should be multiple impl TrustedLen for Flatten<> +// blocks with different bounds on Iterator::Item but the compiler erroneously considers them overlapping +pub unsafe trait TrustedConstSize: IntoIterator {} + +#[unstable(feature = "std_internals", issue = "none")] +unsafe impl<T, const N: usize> TrustedConstSize for [T; N] {} +#[unstable(feature = "std_internals", issue = "none")] +unsafe impl<T, const N: usize> TrustedConstSize for &'_ [T; N] {} +#[unstable(feature = "std_internals", issue = "none")] +unsafe impl<T, const N: usize> TrustedConstSize for &'_ mut [T; N] {} diff --git a/library/core/src/iter/adapters/fuse.rs b/library/core/src/iter/adapters/fuse.rs index aff48b1b220..fbf752c6f20 100644 --- a/library/core/src/iter/adapters/fuse.rs +++ b/library/core/src/iter/adapters/fuse.rs @@ -1,7 +1,8 @@ use crate::intrinsics; -use crate::iter::adapters::{zip::try_get_unchecked, InPlaceIterable, SourceIter}; +use crate::iter::adapters::zip::try_get_unchecked; use crate::iter::{ DoubleEndedIterator, ExactSizeIterator, FusedIterator, TrustedLen, TrustedRandomAccess, + TrustedRandomAccessNoCoerce, }; use crate::ops::Try; @@ -14,7 +15,9 @@ use crate::ops::Try; #[must_use = "iterators are lazy and do nothing unless consumed"] #[stable(feature = "rust1", since = "1.0.0")] pub struct Fuse<I> { - // NOTE: for `I: FusedIterator`, this is always assumed `Some`! + // NOTE: for `I: FusedIterator`, we never bother setting `None`, but + // we still have to be prepared for that state due to variance. + // See rust-lang/rust#85863 iter: Option<I>, } impl<I> Fuse<I> { @@ -42,19 +45,19 @@ macro_rules! fuse { }; } -// NOTE: for `I: FusedIterator`, we assume that the iterator is always `Some`. -// Implementing this as a directly-expanded macro helps codegen performance. -macro_rules! unchecked { - ($self:ident) => { - match $self { - Fuse { iter: Some(iter) } => iter, - // SAFETY: the specialized iterator never sets `None` - Fuse { iter: None } => unsafe { intrinsics::unreachable() }, +/// Specialized macro that doesn't check if the expression is `None`. +/// (We trust that a `FusedIterator` will fuse itself.) +macro_rules! spec { + ($self:ident . iter . $($call:tt)+) => { + match $self.iter { + Some(ref mut iter) => iter.$($call)+, + None => None, } }; } -// Any implementation here is made internal to avoid exposing default fns outside this trait +// Any specialized implementation here is made internal +// to avoid exposing default fns outside this trait. #[stable(feature = "rust1", since = "1.0.0")] impl<I> Iterator for Fuse<I> where @@ -74,17 +77,26 @@ where #[inline] fn last(self) -> Option<Self::Item> { - FuseImpl::last(self) + match self.iter { + Some(iter) => iter.last(), + None => None, + } } #[inline] fn count(self) -> usize { - FuseImpl::count(self) + match self.iter { + Some(iter) => iter.count(), + None => 0, + } } #[inline] fn size_hint(&self) -> (usize, Option<usize>) { - FuseImpl::size_hint(self) + match self.iter { + Some(ref iter) => iter.size_hint(), + None => (0, Some(0)), + } } #[inline] @@ -98,11 +110,14 @@ where } #[inline] - fn fold<Acc, Fold>(self, acc: Acc, fold: Fold) -> Acc + fn fold<Acc, Fold>(self, mut acc: Acc, fold: Fold) -> Acc where Fold: FnMut(Acc, Self::Item) -> Acc, { - FuseImpl::fold(self, acc, fold) + if let Some(iter) = self.iter { + acc = iter.fold(acc, fold); + } + acc } #[inline] @@ -114,9 +129,10 @@ where } #[inline] + #[doc(hidden)] unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item where - Self: TrustedRandomAccess, + Self: TrustedRandomAccessNoCoerce, { match self.iter { // SAFETY: the caller must uphold the contract for @@ -154,11 +170,14 @@ where } #[inline] - fn rfold<Acc, Fold>(self, acc: Acc, fold: Fold) -> Acc + fn rfold<Acc, Fold>(self, mut acc: Acc, fold: Fold) -> Acc where Fold: FnMut(Acc, Self::Item) -> Acc, { - FuseImpl::rfold(self, acc, fold) + if let Some(iter) = self.iter { + acc = iter.rfold(acc, fold); + } + acc } #[inline] @@ -176,11 +195,17 @@ where I: ExactSizeIterator, { fn len(&self) -> usize { - FuseImpl::len(self) + match self.iter { + Some(ref iter) => iter.len(), + None => 0, + } } fn is_empty(&self) -> bool { - FuseImpl::is_empty(self) + match self.iter { + Some(ref iter) => iter.is_empty(), + None => true, + } } } @@ -197,14 +222,21 @@ unsafe impl<I> TrustedLen for Fuse<I> where I: TrustedLen {} // // This is safe to implement as `Fuse` is just forwarding these to the wrapped iterator `I`, which // preserves these properties. -unsafe impl<I> TrustedRandomAccess for Fuse<I> +unsafe impl<I> TrustedRandomAccess for Fuse<I> where I: TrustedRandomAccess {} + +#[doc(hidden)] +#[unstable(feature = "trusted_random_access", issue = "none")] +unsafe impl<I> TrustedRandomAccessNoCoerce for Fuse<I> where - I: TrustedRandomAccess, + I: TrustedRandomAccessNoCoerce, { const MAY_HAVE_SIDE_EFFECT: bool = I::MAY_HAVE_SIDE_EFFECT; } -// Fuse specialization trait +/// Fuse specialization trait +/// +/// We only need to worry about `&mut self` methods, which +/// may exhaust the iterator without consuming it. #[doc(hidden)] trait FuseImpl<I> { type Item; @@ -212,17 +244,11 @@ trait FuseImpl<I> { // Functions specific to any normal Iterators fn next(&mut self) -> Option<Self::Item>; fn nth(&mut self, n: usize) -> Option<Self::Item>; - fn last(self) -> Option<Self::Item>; - fn count(self) -> usize; - fn size_hint(&self) -> (usize, Option<usize>); fn try_fold<Acc, Fold, R>(&mut self, acc: Acc, fold: Fold) -> R where Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, R: Try<Output = Acc>; - fn fold<Acc, Fold>(self, acc: Acc, fold: Fold) -> Acc - where - Fold: FnMut(Acc, Self::Item) -> Acc; fn find<P>(&mut self, predicate: P) -> Option<Self::Item> where P: FnMut(&Self::Item) -> bool; @@ -240,25 +266,13 @@ trait FuseImpl<I> { Fold: FnMut(Acc, Self::Item) -> R, R: Try<Output = Acc>, I: DoubleEndedIterator; - fn rfold<Acc, Fold>(self, acc: Acc, fold: Fold) -> Acc - where - Fold: FnMut(Acc, Self::Item) -> Acc, - I: DoubleEndedIterator; fn rfind<P>(&mut self, predicate: P) -> Option<Self::Item> where P: FnMut(&Self::Item) -> bool, I: DoubleEndedIterator; - - // Functions specific to ExactSizeIterator - fn len(&self) -> usize - where - I: ExactSizeIterator; - fn is_empty(&self) -> bool - where - I: ExactSizeIterator; } -// General Fuse impl +/// General `Fuse` impl which sets `iter = None` when exhausted. #[doc(hidden)] impl<I> FuseImpl<I> for Fuse<I> where @@ -277,30 +291,6 @@ where } #[inline] - default fn last(self) -> Option<I::Item> { - match self.iter { - Some(iter) => iter.last(), - None => None, - } - } - - #[inline] - default fn count(self) -> usize { - match self.iter { - Some(iter) => iter.count(), - None => 0, - } - } - - #[inline] - default fn size_hint(&self) -> (usize, Option<usize>) { - match self.iter { - Some(ref iter) => iter.size_hint(), - None => (0, Some(0)), - } - } - - #[inline] default fn try_fold<Acc, Fold, R>(&mut self, mut acc: Acc, fold: Fold) -> R where Self: Sized, @@ -315,17 +305,6 @@ where } #[inline] - default fn fold<Acc, Fold>(self, mut acc: Acc, fold: Fold) -> Acc - where - Fold: FnMut(Acc, Self::Item) -> Acc, - { - if let Some(iter) = self.iter { - acc = iter.fold(acc, fold); - } - acc - } - - #[inline] default fn find<P>(&mut self, predicate: P) -> Option<Self::Item> where P: FnMut(&Self::Item) -> bool, @@ -365,18 +344,6 @@ where } #[inline] - default fn rfold<Acc, Fold>(self, mut acc: Acc, fold: Fold) -> Acc - where - Fold: FnMut(Acc, Self::Item) -> Acc, - I: DoubleEndedIterator, - { - if let Some(iter) = self.iter { - acc = iter.rfold(acc, fold); - } - acc - } - - #[inline] default fn rfind<P>(&mut self, predicate: P) -> Option<Self::Item> where P: FnMut(&Self::Item) -> bool, @@ -384,30 +351,10 @@ where { fuse!(self.iter.rfind(predicate)) } - - #[inline] - default fn len(&self) -> usize - where - I: ExactSizeIterator, - { - match self.iter { - Some(ref iter) => iter.len(), - None => 0, - } - } - - #[inline] - default fn is_empty(&self) -> bool - where - I: ExactSizeIterator, - { - match self.iter { - Some(ref iter) => iter.is_empty(), - None => true, - } - } } +/// Specialized `Fuse` impl which doesn't bother clearing `iter` when exhausted. +/// However, we must still be prepared for the possibility that it was already cleared! #[doc(hidden)] impl<I> FuseImpl<I> for Fuse<I> where @@ -415,45 +362,25 @@ where { #[inline] fn next(&mut self) -> Option<<I as Iterator>::Item> { - unchecked!(self).next() + spec!(self.iter.next()) } #[inline] fn nth(&mut self, n: usize) -> Option<I::Item> { - unchecked!(self).nth(n) - } - - #[inline] - fn last(self) -> Option<I::Item> { - unchecked!(self).last() + spec!(self.iter.nth(n)) } #[inline] - fn count(self) -> usize { - unchecked!(self).count() - } - - #[inline] - fn size_hint(&self) -> (usize, Option<usize>) { - unchecked!(self).size_hint() - } - - #[inline] - fn try_fold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R + fn try_fold<Acc, Fold, R>(&mut self, mut acc: Acc, fold: Fold) -> R where Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, R: Try<Output = Acc>, { - unchecked!(self).try_fold(init, fold) - } - - #[inline] - fn fold<Acc, Fold>(self, init: Acc, fold: Fold) -> Acc - where - Fold: FnMut(Acc, Self::Item) -> Acc, - { - unchecked!(self).fold(init, fold) + if let Some(ref mut iter) = self.iter { + acc = iter.try_fold(acc, fold)?; + } + try { acc } } #[inline] @@ -461,7 +388,7 @@ where where P: FnMut(&Self::Item) -> bool, { - unchecked!(self).find(predicate) + spec!(self.iter.find(predicate)) } #[inline] @@ -469,7 +396,7 @@ where where I: DoubleEndedIterator, { - unchecked!(self).next_back() + spec!(self.iter.next_back()) } #[inline] @@ -477,27 +404,21 @@ where where I: DoubleEndedIterator, { - unchecked!(self).nth_back(n) + spec!(self.iter.nth_back(n)) } #[inline] - fn try_rfold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R + fn try_rfold<Acc, Fold, R>(&mut self, mut acc: Acc, fold: Fold) -> R where Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, R: Try<Output = Acc>, I: DoubleEndedIterator, { - unchecked!(self).try_rfold(init, fold) - } - - #[inline] - fn rfold<Acc, Fold>(self, init: Acc, fold: Fold) -> Acc - where - Fold: FnMut(Acc, Self::Item) -> Acc, - I: DoubleEndedIterator, - { - unchecked!(self).rfold(init, fold) + if let Some(ref mut iter) = self.iter { + acc = iter.try_rfold(acc, fold)?; + } + try { acc } } #[inline] @@ -506,43 +427,6 @@ where P: FnMut(&Self::Item) -> bool, I: DoubleEndedIterator, { - unchecked!(self).rfind(predicate) - } - - #[inline] - fn len(&self) -> usize - where - I: ExactSizeIterator, - { - unchecked!(self).len() - } - - #[inline] - fn is_empty(&self) -> bool - where - I: ExactSizeIterator, - { - unchecked!(self).is_empty() + spec!(self.iter.rfind(predicate)) } } - -#[unstable(issue = "none", feature = "inplace_iteration")] -unsafe impl<S: Iterator, I: FusedIterator> SourceIter for Fuse<I> -where - I: SourceIter<Source = S>, -{ - type Source = S; - - #[inline] - unsafe fn as_inner(&mut self) -> &mut S { - match self.iter { - // SAFETY: unsafe function forwarding to unsafe function with the same requirements - Some(ref mut iter) => unsafe { SourceIter::as_inner(iter) }, - // SAFETY: the specialized iterator never sets `None` - None => unsafe { intrinsics::unreachable() }, - } - } -} - -#[unstable(issue = "none", feature = "inplace_iteration")] -unsafe impl<I: InPlaceIterable> InPlaceIterable for Fuse<I> {} diff --git a/library/core/src/iter/adapters/map.rs b/library/core/src/iter/adapters/map.rs index 0bf9f4b0327..763e253e75a 100644 --- a/library/core/src/iter/adapters/map.rs +++ b/library/core/src/iter/adapters/map.rs @@ -1,5 +1,7 @@ use crate::fmt; -use crate::iter::adapters::{zip::try_get_unchecked, SourceIter, TrustedRandomAccess}; +use crate::iter::adapters::{ + zip::try_get_unchecked, SourceIter, TrustedRandomAccess, TrustedRandomAccessNoCoerce, +}; use crate::iter::{FusedIterator, InPlaceIterable, TrustedLen}; use crate::ops::Try; @@ -122,9 +124,10 @@ where self.iter.fold(init, map_fold(self.f, g)) } + #[doc(hidden)] unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> B where - Self: TrustedRandomAccess, + Self: TrustedRandomAccessNoCoerce, { // SAFETY: the caller must uphold the contract for // `Iterator::__iterator_get_unchecked`. @@ -186,9 +189,13 @@ where #[doc(hidden)] #[unstable(feature = "trusted_random_access", issue = "none")] -unsafe impl<I, F> TrustedRandomAccess for Map<I, F> +unsafe impl<I, F> TrustedRandomAccess for Map<I, F> where I: TrustedRandomAccess {} + +#[doc(hidden)] +#[unstable(feature = "trusted_random_access", issue = "none")] +unsafe impl<I, F> TrustedRandomAccessNoCoerce for Map<I, F> where - I: TrustedRandomAccess, + I: TrustedRandomAccessNoCoerce, { const MAY_HAVE_SIDE_EFFECT: bool = true; } diff --git a/library/core/src/iter/adapters/mod.rs b/library/core/src/iter/adapters/mod.rs index 9fdd4fca04c..056ccca1d01 100644 --- a/library/core/src/iter/adapters/mod.rs +++ b/library/core/src/iter/adapters/mod.rs @@ -51,10 +51,13 @@ pub use self::map_while::MapWhile; #[unstable(feature = "trusted_random_access", issue = "none")] pub use self::zip::TrustedRandomAccess; +#[unstable(feature = "trusted_random_access", issue = "none")] +pub use self::zip::TrustedRandomAccessNoCoerce; + #[unstable(feature = "iter_zip", issue = "83574")] pub use self::zip::zip; -/// This trait provides transitive access to source-stage in an interator-adapter pipeline +/// This trait provides transitive access to source-stage in an iterator-adapter pipeline /// under the conditions that /// * the iterator source `S` itself implements `SourceIter<Source = S>` /// * there is a delegating implementation of this trait for each adapter in the pipeline between diff --git a/library/core/src/iter/adapters/peekable.rs b/library/core/src/iter/adapters/peekable.rs index 69bd2996efe..91fa1a9ad35 100644 --- a/library/core/src/iter/adapters/peekable.rs +++ b/library/core/src/iter/adapters/peekable.rs @@ -130,7 +130,6 @@ where } #[inline] - #[cfg(not(bootstrap))] fn try_rfold<B, F, R>(&mut self, init: B, mut f: F) -> R where Self: Sized, @@ -151,28 +150,6 @@ where } #[inline] - #[cfg(bootstrap)] - fn try_rfold<B, F, R>(&mut self, init: B, mut f: F) -> R - where - Self: Sized, - F: FnMut(B, Self::Item) -> R, - R: Try<Output = B>, - { - let _use_the_import: ControlFlow<()>; - match self.peeked.take() { - Some(None) => try { init }, - Some(Some(v)) => match self.iter.try_rfold(init, &mut f).into_result() { - Ok(acc) => f(acc, v), - Err(e) => { - self.peeked = Some(Some(v)); - R::from_error(e) - } - }, - None => self.iter.try_rfold(init, f), - } - } - - #[inline] fn rfold<Acc, Fold>(self, init: Acc, mut fold: Fold) -> Acc where Fold: FnMut(Acc, Self::Item) -> Acc, diff --git a/library/core/src/iter/adapters/take.rs b/library/core/src/iter/adapters/take.rs index 92f82ae2325..beda8c32c6b 100644 --- a/library/core/src/iter/adapters/take.rs +++ b/library/core/src/iter/adapters/take.rs @@ -1,8 +1,5 @@ use crate::cmp; -use crate::iter::{ - adapters::zip::try_get_unchecked, adapters::SourceIter, FusedIterator, InPlaceIterable, - TrustedLen, TrustedRandomAccess, -}; +use crate::iter::{adapters::SourceIter, FusedIterator, InPlaceIterable, TrustedLen}; use crate::ops::{ControlFlow, Try}; /// An iterator that only iterates over the first `n` iterations of `iter`. @@ -114,15 +111,6 @@ where self.try_fold(init, ok(fold)).unwrap() } - - unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> <I as Iterator>::Item - where - Self: TrustedRandomAccess, - { - // SAFETY: the caller must uphold the contract for - // `Iterator::__iterator_get_unchecked`. - unsafe { try_get_unchecked(&mut self.iter, idx) } - } } #[unstable(issue = "none", feature = "inplace_iteration")] @@ -219,12 +207,3 @@ impl<I> FusedIterator for Take<I> where I: FusedIterator {} #[unstable(feature = "trusted_len", issue = "37572")] unsafe impl<I: TrustedLen> TrustedLen for Take<I> {} - -#[doc(hidden)] -#[unstable(feature = "trusted_random_access", issue = "none")] -unsafe impl<I> TrustedRandomAccess for Take<I> -where - I: TrustedRandomAccess, -{ - const MAY_HAVE_SIDE_EFFECT: bool = I::MAY_HAVE_SIDE_EFFECT; -} diff --git a/library/core/src/iter/adapters/zip.rs b/library/core/src/iter/adapters/zip.rs index c95324c80ba..c7e69e922c1 100644 --- a/library/core/src/iter/adapters/zip.rs +++ b/library/core/src/iter/adapters/zip.rs @@ -88,9 +88,10 @@ where } #[inline] + #[doc(hidden)] unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item where - Self: TrustedRandomAccess, + Self: TrustedRandomAccessNoCoerce, { // SAFETY: `ZipImpl::__iterator_get_unchecked` has same safety // requirements as `Iterator::__iterator_get_unchecked`. @@ -125,7 +126,66 @@ trait ZipImpl<A, B> { // This has the same safety requirements as `Iterator::__iterator_get_unchecked` unsafe fn get_unchecked(&mut self, idx: usize) -> <Self as Iterator>::Item where - Self: Iterator + TrustedRandomAccess; + Self: Iterator + TrustedRandomAccessNoCoerce; +} + +// Work around limitations of specialization, requiring `default` impls to be repeated +// in intermediary impls. +macro_rules! zip_impl_general_defaults { + () => { + default fn new(a: A, b: B) -> Self { + Zip { + a, + b, + index: 0, // unused + len: 0, // unused + a_len: 0, // unused + } + } + + #[inline] + default fn next(&mut self) -> Option<(A::Item, B::Item)> { + let x = self.a.next()?; + let y = self.b.next()?; + Some((x, y)) + } + + #[inline] + default fn nth(&mut self, n: usize) -> Option<Self::Item> { + self.super_nth(n) + } + + #[inline] + default fn next_back(&mut self) -> Option<(A::Item, B::Item)> + where + A: DoubleEndedIterator + ExactSizeIterator, + B: DoubleEndedIterator + ExactSizeIterator, + { + // The function body below only uses `self.a/b.len()` and `self.a/b.next_back()` + // and doesn’t call `next_back` too often, so this implementation is safe in + // the `TrustedRandomAccessNoCoerce` specialization + + let a_sz = self.a.len(); + let b_sz = self.b.len(); + if a_sz != b_sz { + // Adjust a, b to equal length + if a_sz > b_sz { + for _ in 0..a_sz - b_sz { + self.a.next_back(); + } + } else { + for _ in 0..b_sz - a_sz { + self.b.next_back(); + } + } + } + match (self.a.next_back(), self.b.next_back()) { + (Some(x), Some(y)) => Some((x, y)), + (None, None) => None, + _ => unreachable!(), + } + } + }; } // General Zip impl @@ -136,54 +196,8 @@ where B: Iterator, { type Item = (A::Item, B::Item); - default fn new(a: A, b: B) -> Self { - Zip { - a, - b, - index: 0, // unused - len: 0, // unused - a_len: 0, // unused - } - } - #[inline] - default fn next(&mut self) -> Option<(A::Item, B::Item)> { - let x = self.a.next()?; - let y = self.b.next()?; - Some((x, y)) - } - - #[inline] - default fn nth(&mut self, n: usize) -> Option<Self::Item> { - self.super_nth(n) - } - - #[inline] - default fn next_back(&mut self) -> Option<(A::Item, B::Item)> - where - A: DoubleEndedIterator + ExactSizeIterator, - B: DoubleEndedIterator + ExactSizeIterator, - { - let a_sz = self.a.len(); - let b_sz = self.b.len(); - if a_sz != b_sz { - // Adjust a, b to equal length - if a_sz > b_sz { - for _ in 0..a_sz - b_sz { - self.a.next_back(); - } - } else { - for _ in 0..b_sz - a_sz { - self.b.next_back(); - } - } - } - match (self.a.next_back(), self.b.next_back()) { - (Some(x), Some(y)) => Some((x, y)), - (None, None) => None, - _ => unreachable!(), - } - } + zip_impl_general_defaults! {} #[inline] default fn size_hint(&self) -> (usize, Option<usize>) { @@ -204,7 +218,7 @@ where default unsafe fn get_unchecked(&mut self, _idx: usize) -> <Self as Iterator>::Item where - Self: TrustedRandomAccess, + Self: TrustedRandomAccessNoCoerce, { unreachable!("Always specialized"); } @@ -213,6 +227,29 @@ where #[doc(hidden)] impl<A, B> ZipImpl<A, B> for Zip<A, B> where + A: TrustedRandomAccessNoCoerce + Iterator, + B: TrustedRandomAccessNoCoerce + Iterator, +{ + zip_impl_general_defaults! {} + + #[inline] + default fn size_hint(&self) -> (usize, Option<usize>) { + let size = cmp::min(self.a.size(), self.b.size()); + (size, Some(size)) + } + + #[inline] + unsafe fn get_unchecked(&mut self, idx: usize) -> <Self as Iterator>::Item { + let idx = self.index + idx; + // SAFETY: the caller must uphold the contract for + // `Iterator::__iterator_get_unchecked`. + unsafe { (self.a.__iterator_get_unchecked(idx), self.b.__iterator_get_unchecked(idx)) } + } +} + +#[doc(hidden)] +impl<A, B> ZipImpl<A, B> for Zip<A, B> +where A: TrustedRandomAccess + Iterator, B: TrustedRandomAccess + Iterator, { @@ -226,6 +263,8 @@ where fn next(&mut self) -> Option<(A::Item, B::Item)> { if self.index < self.len { let i = self.index; + // since get_unchecked executes code which can panic we increment the counters beforehand + // so that the same index won't be accessed twice, as required by TrustedRandomAccess self.index += 1; // SAFETY: `i` is smaller than `self.len`, thus smaller than `self.a.len()` and `self.b.len()` unsafe { @@ -233,6 +272,7 @@ where } } else if A::MAY_HAVE_SIDE_EFFECT && self.index < self.a_len { let i = self.index; + // as above, increment before executing code that may panic self.index += 1; self.len += 1; // match the base implementation's potential side effects @@ -258,6 +298,8 @@ where let end = self.index + delta; while self.index < end { let i = self.index; + // since get_unchecked executes code which can panic we increment the counters beforehand + // so that the same index won't be accessed twice, as required by TrustedRandomAccess self.index += 1; if A::MAY_HAVE_SIDE_EFFECT { // SAFETY: the usage of `cmp::min` to calculate `delta` @@ -294,9 +336,12 @@ where let sz_a = self.a.size(); if A::MAY_HAVE_SIDE_EFFECT && sz_a > self.len { for _ in 0..sz_a - self.len { + // since next_back() may panic we increment the counters beforehand + // to keep Zip's state in sync with the underlying iterator source + self.a_len -= 1; self.a.next_back(); } - self.a_len = self.len; + debug_assert_eq!(self.a_len, self.len); } let sz_b = self.b.size(); if B::MAY_HAVE_SIDE_EFFECT && sz_b > self.len { @@ -307,6 +352,8 @@ where } } if self.index < self.len { + // since get_unchecked executes code which can panic we increment the counters beforehand + // so that the same index won't be accessed twice, as required by TrustedRandomAccess self.len -= 1; self.a_len -= 1; let i = self.len; @@ -319,14 +366,6 @@ where None } } - - #[inline] - unsafe fn get_unchecked(&mut self, idx: usize) -> <Self as Iterator>::Item { - let idx = self.index + idx; - // SAFETY: the caller must uphold the contract for - // `Iterator::__iterator_get_unchecked`. - unsafe { (self.a.__iterator_get_unchecked(idx), self.b.__iterator_get_unchecked(idx)) } - } } #[stable(feature = "rust1", since = "1.0.0")] @@ -344,6 +383,15 @@ where A: TrustedRandomAccess, B: TrustedRandomAccess, { +} + +#[doc(hidden)] +#[unstable(feature = "trusted_random_access", issue = "none")] +unsafe impl<A, B> TrustedRandomAccessNoCoerce for Zip<A, B> +where + A: TrustedRandomAccessNoCoerce, + B: TrustedRandomAccessNoCoerce, +{ const MAY_HAVE_SIDE_EFFECT: bool = A::MAY_HAVE_SIDE_EFFECT || B::MAY_HAVE_SIDE_EFFECT; } @@ -406,7 +454,9 @@ impl<A: Debug, B: Debug> ZipFmt<A, B> for Zip<A, B> { } } -impl<A: Debug + TrustedRandomAccess, B: Debug + TrustedRandomAccess> ZipFmt<A, B> for Zip<A, B> { +impl<A: Debug + TrustedRandomAccessNoCoerce, B: Debug + TrustedRandomAccessNoCoerce> ZipFmt<A, B> + for Zip<A, B> +{ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { // It's *not safe* to call fmt on the contained iterators, since once // we start iterating they're in strange, potentially unsafe, states. @@ -420,34 +470,70 @@ impl<A: Debug + TrustedRandomAccess, B: Debug + TrustedRandomAccess> ZipFmt<A, B /// /// The iterator's `size_hint` must be exact and cheap to call. /// -/// `size` may not be overridden. +/// `TrustedRandomAccessNoCoerce::size` may not be overridden. +/// +/// All subtypes and all supertypes of `Self` must also implement `TrustedRandomAccess`. +/// In particular, this means that types with non-invariant parameters usually can not have +/// an impl for `TrustedRandomAccess` that depends on any trait bounds on such parameters, except +/// for bounds that come from the respective struct/enum definition itself, or bounds involving +/// traits that themselves come with a guarantee similar to this one. +/// +/// If `Self: ExactSizeIterator` then `self.len()` must always produce results consistent +/// with `self.size()`. /// -/// `<Self as Iterator>::__iterator_get_unchecked` must be safe to call -/// provided the following conditions are met. +/// If `Self: Iterator`, then `<Self as Iterator>::__iterator_get_unchecked(&mut self, idx)` +/// must be safe to call provided the following conditions are met. /// /// 1. `0 <= idx` and `idx < self.size()`. -/// 2. If `self: !Clone`, then `get_unchecked` is never called with the same +/// 2. If `Self: !Clone`, then `self.__iterator_get_unchecked(idx)` is never called with the same /// index on `self` more than once. -/// 3. After `self.get_unchecked(idx)` has been called then `next_back` will -/// only be called at most `self.size() - idx - 1` times. -/// 4. After `get_unchecked` is called, then only the following methods will be -/// called on `self`: -/// * `std::clone::Clone::clone()` -/// * `std::iter::Iterator::size_hint()` -/// * `std::iter::DoubleEndedIterator::next_back()` -/// * `std::iter::Iterator::__iterator_get_unchecked()` -/// * `std::iter::TrustedRandomAccess::size()` +/// 3. After `self.__iterator_get_unchecked(idx)` has been called, then `self.next_back()` will +/// only be called at most `self.size() - idx - 1` times. If `Self: Clone` and `self` is cloned, +/// then this number is calculated for `self` and its clone individually, +/// but `self.next_back()` calls that happened before the cloning count for both `self` and the clone. +/// 4. After `self.__iterator_get_unchecked(idx)` has been called, then only the following methods +/// will be called on `self` or on any new clones of `self`: +/// * `std::clone::Clone::clone` +/// * `std::iter::Iterator::size_hint` +/// * `std::iter::DoubleEndedIterator::next_back` +/// * `std::iter::ExactSizeIterator::len` +/// * `std::iter::Iterator::__iterator_get_unchecked` +/// * `std::iter::TrustedRandomAccessNoCoerce::size` +/// 5. If `T` is a subtype of `Self`, then `self` is allowed to be coerced +/// to `T`. If `self` is coerced to `T` after `self.__iterator_get_unchecked(idx)` has already +/// been called, then no methods except for the ones listed under 4. are allowed to be called +/// on the resulting value of type `T`, either. Multiple such coercion steps are allowed. +/// Regarding 2. and 3., the number of times `__iterator_get_unchecked(idx)` or `next_back()` is +/// called on `self` and the resulting value of type `T` (and on further coercion results with +/// sub-subtypes) are added together and their sums must not exceed the specified bounds. /// /// Further, given that these conditions are met, it must guarantee that: /// /// * It does not change the value returned from `size_hint` /// * It must be safe to call the methods listed above on `self` after calling -/// `get_unchecked`, assuming that the required traits are implemented. -/// * It must also be safe to drop `self` after calling `get_unchecked`. +/// `self.__iterator_get_unchecked(idx)`, assuming that the required traits are implemented. +/// * It must also be safe to drop `self` after calling `self.__iterator_get_unchecked(idx)`. +/// * If `T` is a subtype of `Self`, then it must be safe to coerce `self` to `T`. +// +// FIXME: Clarify interaction with SourceIter/InPlaceIterable. Calling `SouceIter::as_inner` +// after `__iterator_get_unchecked` is supposed to be allowed. +#[doc(hidden)] +#[unstable(feature = "trusted_random_access", issue = "none")] +#[rustc_specialization_trait] +pub unsafe trait TrustedRandomAccess: TrustedRandomAccessNoCoerce {} + +/// Like [`TrustedRandomAccess`] but without any of the requirements / guarantees around +/// coercions to subtypes after `__iterator_get_unchecked` (they aren’t allowed here!), and +/// without the requirement that subtypes / supertypes implement `TrustedRandomAccessNoCoerce`. +/// +/// This trait was created in PR #85874 to fix soundness issue #85873 without performance regressions. +/// It is subject to change as we might want to build a more generally useful (for performance +/// optimizations) and more sophisticated trait or trait hierarchy that replaces or extends +/// [`TrustedRandomAccess`] and `TrustedRandomAccessNoCoerce`. #[doc(hidden)] #[unstable(feature = "trusted_random_access", issue = "none")] #[rustc_specialization_trait] -pub unsafe trait TrustedRandomAccess: Sized { +pub unsafe trait TrustedRandomAccessNoCoerce: Sized { // Convenience method. fn size(&self) -> usize where @@ -488,7 +574,7 @@ unsafe impl<I: Iterator> SpecTrustedRandomAccess for I { } } -unsafe impl<I: Iterator + TrustedRandomAccess> SpecTrustedRandomAccess for I { +unsafe impl<I: Iterator + TrustedRandomAccessNoCoerce> SpecTrustedRandomAccess for I { unsafe fn try_get_unchecked(&mut self, index: usize) -> Self::Item { // SAFETY: the caller must uphold the contract for // `Iterator::__iterator_get_unchecked`. diff --git a/library/core/src/iter/mod.rs b/library/core/src/iter/mod.rs index bfb27da505e..7fb80f954ff 100644 --- a/library/core/src/iter/mod.rs +++ b/library/core/src/iter/mod.rs @@ -336,7 +336,7 @@ //! This will print the numbers `0` through `4`, each on their own line. //! //! Bear in mind that methods on infinite iterators, even those for which a -//! result can be determined mathematically in finite time, may not terminate. +//! result can be determined mathematically in finite time, might not terminate. //! Specifically, methods such as [`min`], which in the general case require //! traversing every element in the iterator, are likely not to return //! successfully for any infinite iterators. @@ -407,6 +407,8 @@ pub use self::adapters::SourceIter; pub use self::adapters::StepBy; #[unstable(feature = "trusted_random_access", issue = "none")] pub use self::adapters::TrustedRandomAccess; +#[unstable(feature = "trusted_random_access", issue = "none")] +pub use self::adapters::TrustedRandomAccessNoCoerce; #[stable(feature = "rust1", since = "1.0.0")] pub use self::adapters::{ Chain, Cycle, Enumerate, Filter, FilterMap, FlatMap, Fuse, Inspect, Map, Peekable, Rev, Scan, diff --git a/library/core/src/iter/range.rs b/library/core/src/iter/range.rs index de5d77e96ee..f7ed811e447 100644 --- a/library/core/src/iter/range.rs +++ b/library/core/src/iter/range.rs @@ -3,7 +3,9 @@ use crate::convert::TryFrom; use crate::mem; use crate::ops::{self, Try}; -use super::{FusedIterator, TrustedLen, TrustedRandomAccess, TrustedStep}; +use super::{ + FusedIterator, TrustedLen, TrustedRandomAccess, TrustedRandomAccessNoCoerce, TrustedStep, +}; // Safety: All invariants are upheld. macro_rules! unsafe_impl_trusted_step { @@ -30,7 +32,7 @@ pub trait Step: Clone + PartialOrd + Sized { /// For any `a`, `b`, and `n`: /// /// * `steps_between(&a, &b) == Some(n)` if and only if `Step::forward_checked(&a, n) == Some(b)` - /// * `steps_between(&a, &b) == Some(n)` if and only if `Step::backward_checked(&a, n) == Some(a)` + /// * `steps_between(&a, &b) == Some(n)` if and only if `Step::backward_checked(&b, n) == Some(a)` /// * `steps_between(&a, &b) == Some(n)` only if `a <= b` /// * Corollary: `steps_between(&a, &b) == Some(0)` if and only if `a == b` /// * Note that `a <= b` does _not_ imply `steps_between(&a, &b) != None`; @@ -275,7 +277,7 @@ macro_rules! step_integer_impls { // // Casting to isize extends the width but preserves the sign. // Use wrapping_sub in isize space and cast to usize to compute - // the difference that may not fit inside the range of isize. + // the difference that might not fit inside the range of isize. Some((*end as isize).wrapping_sub(*start as isize) as usize) } else { None @@ -495,7 +497,11 @@ macro_rules! unsafe_range_trusted_random_access_impl { ($($t:ty)*) => ($( #[doc(hidden)] #[unstable(feature = "trusted_random_access", issue = "none")] - unsafe impl TrustedRandomAccess for ops::Range<$t> { + unsafe impl TrustedRandomAccess for ops::Range<$t> {} + + #[doc(hidden)] + #[unstable(feature = "trusted_random_access", issue = "none")] + unsafe impl TrustedRandomAccessNoCoerce for ops::Range<$t> { const MAY_HAVE_SIDE_EFFECT: bool = false; } )*) @@ -667,9 +673,10 @@ impl<A: Step> Iterator for ops::Range<A> { } #[inline] + #[doc(hidden)] unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item where - Self: TrustedRandomAccess, + Self: TrustedRandomAccessNoCoerce, { // SAFETY: The TrustedRandomAccess contract requires that callers only pass an index // that is in bounds. diff --git a/library/core/src/iter/sources/empty.rs b/library/core/src/iter/sources/empty.rs index 919c564f287..a7d4646f5c5 100644 --- a/library/core/src/iter/sources/empty.rs +++ b/library/core/src/iter/sources/empty.rs @@ -85,7 +85,8 @@ impl<T> Clone for Empty<T> { // not #[derive] because that adds a Default bound on T, // which isn't necessary. #[stable(feature = "iter_empty", since = "1.2.0")] -impl<T> Default for Empty<T> { +#[rustc_const_unstable(feature = "const_default_impls", issue = "87864")] +impl<T> const Default for Empty<T> { fn default() -> Empty<T> { Empty(marker::PhantomData) } diff --git a/library/core/src/iter/sources/repeat.rs b/library/core/src/iter/sources/repeat.rs index a9478041c69..733142ed011 100644 --- a/library/core/src/iter/sources/repeat.rs +++ b/library/core/src/iter/sources/repeat.rs @@ -51,6 +51,7 @@ use crate::iter::{FusedIterator, TrustedLen}; /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr(not(test), rustc_diagnostic_item = "iter_repeat")] pub fn repeat<T: Clone>(elt: T) -> Repeat<T> { Repeat { element: elt } } diff --git a/library/core/src/iter/traits/accum.rs b/library/core/src/iter/traits/accum.rs index 0a4210a78e3..c2e837df5ff 100644 --- a/library/core/src/iter/traits/accum.rs +++ b/library/core/src/iter/traits/accum.rs @@ -3,12 +3,11 @@ use crate::num::Wrapping; /// Trait to represent types that can be created by summing up an iterator. /// -/// This trait is used to implement the [`sum()`] method on iterators. Types which -/// implement the trait can be generated by the [`sum()`] method. Like -/// [`FromIterator`] this trait should rarely be called directly and instead -/// interacted with through [`Iterator::sum()`]. +/// This trait is used to implement [`Iterator::sum()`]. Types which implement +/// this trait can be generated by using the [`sum()`] method on an iterator. +/// Like [`FromIterator`], this trait should rarely be called directly. /// -/// [`sum()`]: Sum::sum +/// [`sum()`]: Iterator::sum /// [`FromIterator`]: iter::FromIterator #[stable(feature = "iter_arith_traits", since = "1.12.0")] pub trait Sum<A = Self>: Sized { @@ -21,12 +20,11 @@ pub trait Sum<A = Self>: Sized { /// Trait to represent types that can be created by multiplying elements of an /// iterator. /// -/// This trait is used to implement the [`product()`] method on iterators. Types -/// which implement the trait can be generated by the [`product()`] method. Like -/// [`FromIterator`] this trait should rarely be called directly and instead -/// interacted with through [`Iterator::product()`]. +/// This trait is used to implement [`Iterator::product()`]. Types which implement +/// this trait can be generated by using the [`product()`] method on an iterator. +/// Like [`FromIterator`], this trait should rarely be called directly. /// -/// [`product()`]: Product::product +/// [`product()`]: Iterator::product /// [`FromIterator`]: iter::FromIterator #[stable(feature = "iter_arith_traits", since = "1.12.0")] pub trait Product<A = Self>: Sized { diff --git a/library/core/src/iter/traits/collect.rs b/library/core/src/iter/traits/collect.rs index e2a407509b1..aa91346851f 100644 --- a/library/core/src/iter/traits/collect.rs +++ b/library/core/src/iter/traits/collect.rs @@ -89,6 +89,7 @@ over elements of type `{A}`", label = "value of type `{Self}` cannot be built from `std::iter::Iterator<Item={A}>`" )] +#[rustc_diagnostic_item = "FromIterator"] pub trait FromIterator<A>: Sized { /// Creates a value from an iterator. /// @@ -238,6 +239,7 @@ impl<I: Iterator> IntoIterator for I { type Item = I::Item; type IntoIter = I; + #[inline] fn into_iter(self) -> I { self } @@ -358,3 +360,61 @@ impl Extend<()> for () { } fn extend_one(&mut self, _item: ()) {} } + +#[stable(feature = "extend_for_tuple", since = "1.56.0")] +impl<A, B, ExtendA, ExtendB> Extend<(A, B)> for (ExtendA, ExtendB) +where + ExtendA: Extend<A>, + ExtendB: Extend<B>, +{ + /// Allows to `extend` a tuple of collections that also implement `Extend`. + /// + /// See also: [`Iterator::unzip`] + /// + /// # Examples + /// ``` + /// let mut tuple = (vec![0], vec![1]); + /// tuple.extend(vec![(2, 3), (4, 5), (6, 7)]); + /// assert_eq!(tuple.0, vec![0, 2, 4, 6]); + /// assert_eq!(tuple.1, vec![1, 3, 5, 7]); + /// + /// // also allows for arbitrarily nested tuples + /// let mut nested_tuple = (vec![(1, -1)], vec![(2, -2)]); + /// nested_tuple.extend(vec![((3, -3), (4, -4)), ((5, -5), (6, -6))]); + /// + /// assert_eq!(nested_tuple.0, vec![(1, -1), (3, -3), (5, -5)]); + /// assert_eq!(nested_tuple.1, vec![(2, -2), (4, -4), (6, -6)]); + /// ``` + fn extend<T: IntoIterator<Item = (A, B)>>(&mut self, into_iter: T) { + let (a, b) = self; + let iter = into_iter.into_iter(); + + fn extend<'a, A, B>( + a: &'a mut impl Extend<A>, + b: &'a mut impl Extend<B>, + ) -> impl FnMut((), (A, B)) + 'a { + move |(), (t, u)| { + a.extend_one(t); + b.extend_one(u); + } + } + + let (lower_bound, _) = iter.size_hint(); + if lower_bound > 0 { + a.extend_reserve(lower_bound); + b.extend_reserve(lower_bound); + } + + iter.fold((), extend(a, b)); + } + + fn extend_one(&mut self, item: (A, B)) { + self.0.extend_one(item.0); + self.1.extend_one(item.1); + } + + fn extend_reserve(&mut self, additional: usize) { + self.0.extend_reserve(additional); + self.1.extend_reserve(additional); + } +} diff --git a/library/core/src/iter/traits/double_ended.rs b/library/core/src/iter/traits/double_ended.rs index c302502b3b7..9a9cf200770 100644 --- a/library/core/src/iter/traits/double_ended.rs +++ b/library/core/src/iter/traits/double_ended.rs @@ -36,6 +36,7 @@ use crate::ops::{ControlFlow, Try}; /// assert_eq!(None, iter.next_back()); /// ``` #[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr(not(test), rustc_diagnostic_item = "DoubleEndedIterator")] pub trait DoubleEndedIterator: Iterator { /// Removes and returns an element from the end of the iterator. /// @@ -248,6 +249,11 @@ pub trait DoubleEndedIterator: Iterator { /// Folding is useful whenever you have a collection of something, and want /// to produce a single value from it. /// + /// Note: `rfold()` combines elements in a *right-associative* fashion. For associative + /// operators like `+`, the order the elements are combined in is not important, but for non-associative + /// operators like `-` the order will affect the final result. + /// For a *left-associative* version of `rfold()`, see [`Iterator::fold()`]. + /// /// # Examples /// /// Basic usage: @@ -262,7 +268,8 @@ pub trait DoubleEndedIterator: Iterator { /// assert_eq!(sum, 6); /// ``` /// - /// This example builds a string, starting with an initial value + /// This example demonstrates the right-associative nature of `rfold()`: + /// it builds a string, starting with an initial value /// and continuing with each element from the back until the front: /// /// ``` @@ -276,6 +283,7 @@ pub trait DoubleEndedIterator: Iterator { /// /// assert_eq!(result, "(1 + (2 + (3 + (4 + (5 + 0)))))"); /// ``` + #[doc(alias = "foldr")] #[inline] #[stable(feature = "iter_rfold", since = "1.27.0")] fn rfold<B, F>(mut self, init: B, mut f: F) -> B diff --git a/library/core/src/iter/traits/exact_size.rs b/library/core/src/iter/traits/exact_size.rs index 167db3359f2..a476799b70d 100644 --- a/library/core/src/iter/traits/exact_size.rs +++ b/library/core/src/iter/traits/exact_size.rs @@ -97,7 +97,6 @@ pub trait ExactSizeIterator: Iterator { /// /// assert_eq!(5, five.len()); /// ``` - #[doc(alias = "length")] #[inline] #[stable(feature = "rust1", since = "1.0.0")] fn len(&self) -> usize { diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index 96b924f6e2a..524d8f857e2 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -1,11 +1,7 @@ -// ignore-tidy-filelength -// This file almost exclusively consists of the definition of `Iterator`. We -// can't split that into multiple files. - use crate::cmp::{self, Ordering}; use crate::ops::{ControlFlow, Try}; -use super::super::TrustedRandomAccess; +use super::super::TrustedRandomAccessNoCoerce; use super::super::{Chain, Cloned, Copied, Cycle, Enumerate, Filter, FilterMap, Fuse}; use super::super::{FlatMap, Flatten}; use super::super::{FromIterator, Intersperse, IntersperseWith, Product, Sum, Zip}; @@ -138,7 +134,7 @@ pub trait Iterator { /// A more complex example: /// /// ``` - /// // The even numbers from zero to ten. + /// // The even numbers in the range of zero to nine. /// let iter = (0..10).filter(|x| x % 2 == 0); /// /// // We might iterate from zero to ten times. Knowing that it's five @@ -333,21 +329,22 @@ pub trait Iterator { /// regardless of the step given. /// /// Note 2: The time at which ignored elements are pulled is not fixed. - /// `StepBy` behaves like the sequence `next(), nth(step-1), nth(step-1), …`, - /// but is also free to behave like the sequence - /// `advance_n_and_return_first(step), advance_n_and_return_first(step), …` + /// `StepBy` behaves like the sequence `self.next()`, `self.nth(step-1)`, + /// `self.nth(step-1)`, …, but is also free to behave like the sequence + /// `advance_n_and_return_first(&mut self, step)`, + /// `advance_n_and_return_first(&mut self, step)`, … /// Which way is used may change for some iterators for performance reasons. /// The second way will advance the iterator earlier and may consume more items. /// /// `advance_n_and_return_first` is the equivalent of: /// ``` - /// fn advance_n_and_return_first<I>(iter: &mut I, total_step: usize) -> Option<I::Item> + /// fn advance_n_and_return_first<I>(iter: &mut I, n: usize) -> Option<I::Item> /// where /// I: Iterator, /// { /// let next = iter.next(); - /// if total_step > 1 { - /// iter.nth(total_step-2); + /// if n > 1 { + /// iter.nth(n - 2); /// } /// next /// } @@ -693,7 +690,7 @@ pub trait Iterator { /// more idiomatic to use a `for` loop, but `for_each` may be more legible /// when processing items at the end of longer iterator chains. In some /// cases `for_each` may also be faster than a loop, because it will use - /// internal iteration on adaptors like `Chain`. + /// internal iteration on adapters like `Chain`. /// /// [`for`]: ../../book/ch03-05-control-flow.html#looping-through-a-collection-with-for /// @@ -1292,7 +1289,7 @@ pub trait Iterator { Take::new(self, n) } - /// An iterator adaptor similar to [`fold`] that holds internal state and + /// An iterator adapter similar to [`fold`] that holds internal state and /// produces a new iterator. /// /// [`fold`]: Iterator::fold @@ -1603,7 +1600,7 @@ pub trait Iterator { /// Borrows an iterator, rather than consuming it. /// - /// This is useful to allow applying iterator adaptors while still + /// This is useful to allow applying iterator adapters while still /// retaining ownership of the original iterator. /// /// # Examples @@ -1959,6 +1956,31 @@ pub trait Iterator { /// assert_eq!(it.len(), 2); /// assert_eq!(it.next(), Some(&40)); /// ``` + /// + /// While you cannot `break` from a closure, the [`crate::ops::ControlFlow`] + /// type allows a similar idea: + /// + /// ``` + /// use std::ops::ControlFlow; + /// + /// let triangular = (1..30).try_fold(0_i8, |prev, x| { + /// if let Some(next) = prev.checked_add(x) { + /// ControlFlow::Continue(next) + /// } else { + /// ControlFlow::Break(prev) + /// } + /// }); + /// assert_eq!(triangular, ControlFlow::Break(120)); + /// + /// let triangular = (1..30).try_fold(0_u64, |prev, x| { + /// if let Some(next) = prev.checked_add(x) { + /// ControlFlow::Continue(next) + /// } else { + /// ControlFlow::Break(prev) + /// } + /// }); + /// assert_eq!(triangular, ControlFlow::Continue(435)); + /// ``` #[inline] #[stable(feature = "iterator_try_fold", since = "1.27.0")] fn try_fold<B, F, R>(&mut self, init: B, mut f: F) -> R @@ -2001,6 +2023,22 @@ pub trait Iterator { /// // It short-circuited, so the remaining items are still in the iterator: /// assert_eq!(it.next(), Some("stale_bread.json")); /// ``` + /// + /// The [`crate::ops::ControlFlow`] type can be used with this method for the + /// situations in which you'd use `break` and `continue` in a normal loop: + /// + /// ``` + /// use std::ops::ControlFlow; + /// + /// let r = (2..100).try_for_each(|x| { + /// if 323 % x == 0 { + /// return ControlFlow::Break(x) + /// } + /// + /// ControlFlow::Continue(()) + /// }); + /// assert_eq!(r, ControlFlow::Break(17)); + /// ``` #[inline] #[stable(feature = "iterator_try_fold", since = "1.27.0")] fn try_for_each<F, R>(&mut self, f: F) -> R @@ -2036,12 +2074,17 @@ pub trait Iterator { /// to produce a single value from it. /// /// Note: `fold()`, and similar methods that traverse the entire iterator, - /// may not terminate for infinite iterators, even on traits for which a + /// might not terminate for infinite iterators, even on traits for which a /// result is determinable in finite time. /// /// Note: [`reduce()`] can be used to use the first element as the initial /// value, if the accumulator type and item type is the same. /// + /// Note: `fold()` combines elements in a *left-associative* fashion. For associative + /// operators like `+`, the order the elements are combined in is not important, but for non-associative + /// operators like `-` the order will affect the final result. + /// For a *right-associative* version of `fold()`, see [`DoubleEndedIterator::rfold()`]. + /// /// # Note to Implementors /// /// Several of the other (forward) methods have default implementations in @@ -2075,6 +2118,21 @@ pub trait Iterator { /// /// And so, our final result, `6`. /// + /// This example demonstrates the left-associative nature of `fold()`: + /// it builds a string, starting with an initial value + /// and continuing with each element from the front until the back: + /// + /// ``` + /// let numbers = [1, 2, 3, 4, 5]; + /// + /// let zero = "0".to_string(); + /// + /// let result = numbers.iter().fold(zero, |acc, &x| { + /// format!("({} + {})", acc, x) + /// }); + /// + /// assert_eq!(result, "(((((0 + 1) + 2) + 3) + 4) + 5)"); + /// ``` /// It's common for people who haven't used iterators a lot to /// use a `for` loop with a list of things to build up a result. Those /// can be turned into `fold()`s: @@ -2099,7 +2157,7 @@ pub trait Iterator { /// ``` /// /// [`reduce()`]: Iterator::reduce - #[doc(alias = "inject")] + #[doc(alias = "inject", alias = "foldl")] #[inline] #[stable(feature = "rust1", since = "1.0.0")] fn fold<B, F>(mut self, init: B, mut f: F) -> B @@ -2193,7 +2251,6 @@ pub trait Iterator { /// // we can still use `iter`, as there are more elements. /// assert_eq!(iter.next(), Some(&3)); /// ``` - #[doc(alias = "every")] #[inline] #[stable(feature = "rust1", since = "1.0.0")] fn all<F>(&mut self, f: F) -> bool @@ -2378,7 +2435,6 @@ pub trait Iterator { /// ``` #[inline] #[unstable(feature = "try_find", reason = "new API", issue = "63178")] - #[cfg(not(bootstrap))] fn try_find<F, R, E>(&mut self, f: F) -> Result<Option<Self::Item>, E> where Self: Sized, @@ -2405,32 +2461,6 @@ pub trait Iterator { self.try_fold((), check(f)).break_value().transpose() } - /// We're bootstrapping. - #[inline] - #[unstable(feature = "try_find", reason = "new API", issue = "63178")] - #[cfg(bootstrap)] - fn try_find<F, R>(&mut self, f: F) -> Result<Option<Self::Item>, R::Error> - where - Self: Sized, - F: FnMut(&Self::Item) -> R, - R: Try<Output = bool>, - { - #[inline] - fn check<F, T, R>(mut f: F) -> impl FnMut((), T) -> ControlFlow<Result<T, R::Error>> - where - F: FnMut(&T) -> R, - R: Try<Output = bool>, - { - move |(), x| match f(&x).into_result() { - Ok(false) => ControlFlow::CONTINUE, - Ok(true) => ControlFlow::Break(Ok(x)), - Err(x) => ControlFlow::Break(Err(x)), - } - } - - self.try_fold((), check(f)).break_value().transpose() - } - /// Searches for an element in an iterator, returning its index. /// /// `position()` takes a closure that returns `true` or `false`. It applies @@ -2811,6 +2841,14 @@ pub trait Iterator { /// /// assert_eq!(left, [1, 3]); /// assert_eq!(right, [2, 4]); + /// + /// // you can also unzip multiple nested tuples at once + /// let a = [(1, (2, 3)), (4, (5, 6))]; + /// + /// let (x, (y, z)): (Vec<_>, (Vec<_>, Vec<_>)) = a.iter().cloned().unzip(); + /// assert_eq!(x, [1, 4]); + /// assert_eq!(y, [2, 5]); + /// assert_eq!(z, [3, 6]); /// ``` #[stable(feature = "rust1", since = "1.0.0")] fn unzip<A, B, FromA, FromB>(self) -> (FromA, FromB) @@ -2819,28 +2857,9 @@ pub trait Iterator { FromB: Default + Extend<B>, Self: Sized + Iterator<Item = (A, B)>, { - fn extend<'a, A, B>( - ts: &'a mut impl Extend<A>, - us: &'a mut impl Extend<B>, - ) -> impl FnMut((), (A, B)) + 'a { - move |(), (t, u)| { - ts.extend_one(t); - us.extend_one(u); - } - } - - let mut ts: FromA = Default::default(); - let mut us: FromB = Default::default(); - - let (lower_bound, _) = self.size_hint(); - if lower_bound > 0 { - ts.extend_reserve(lower_bound); - us.extend_reserve(lower_bound); - } - - self.fold((), extend(&mut ts, &mut us)); - - (ts, us) + let mut unzipped: (FromA, FromB) = Default::default(); + unzipped.extend(self); + unzipped } /// Creates an iterator which copies all of its elements. @@ -3422,7 +3441,7 @@ pub trait Iterator { self.map(f).is_sorted() } - /// See [TrustedRandomAccess] + /// See [TrustedRandomAccess][super::super::TrustedRandomAccess] // The unusual name is to avoid name collisions in method resolution // see #76479. #[inline] @@ -3430,7 +3449,7 @@ pub trait Iterator { #[unstable(feature = "trusted_random_access", issue = "none")] unsafe fn __iterator_get_unchecked(&mut self, _idx: usize) -> Self::Item where - Self: TrustedRandomAccess, + Self: TrustedRandomAccessNoCoerce, { unreachable!("Always specialized"); } diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index d4e4c5b0d3e..4ab7cc24a0d 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -49,6 +49,10 @@ // // This cfg won't affect doc tests. #![cfg(not(test))] +// To run libcore tests without x.py without ending up with two copies of libcore, Miri needs to be +// able to "empty" this crate. See <https://github.com/rust-lang/miri-test-libstd/issues/4>. +// rustc itself never sets the feature, so this line has no affect there. +#![cfg(any(not(feature = "miri-test-libstd"), test, doctest))] #![stable(feature = "core", since = "1.6.0")] #![doc( html_playground_url = "https://play.rust-lang.org/", @@ -57,61 +61,76 @@ test(attr(allow(dead_code, deprecated, unused_variables, unused_mut))) )] #![no_core] +// +// Lints: +#![deny(rust_2021_incompatible_or_patterns)] +#![deny(unsafe_op_in_unsafe_fn)] #![warn(deprecated_in_future)] -#![warn(missing_docs)] #![warn(missing_debug_implementations)] +#![warn(missing_docs)] #![allow(explicit_outlives_requirements)] -#![feature(rustc_allow_const_fn_unstable)] -#![feature(allow_internal_unstable)] -#![feature(arbitrary_self_types)] -#![feature(asm)] -#![feature(cfg_target_has_atomic)] -#![feature(const_heap)] +// +// Library features for const fns: +#![feature(const_align_of_val)] #![feature(const_alloc_layout)] +#![feature(const_arguments_as_str)] #![feature(const_assert_type)] -#![feature(const_discriminant)] +#![feature(const_caller_location)] #![feature(const_cell_into_inner)] -#![feature(const_intrinsic_copy)] -#![feature(const_intrinsic_forget)] -#![feature(const_float_classify)] +#![feature(const_discriminant)] #![feature(const_float_bits_conv)] -#![feature(const_int_unchecked_arith)] +#![feature(const_float_classify)] +#![feature(const_heap)] #![feature(const_inherent_unchecked_arith)] -#![feature(const_mut_refs)] -#![feature(const_refs_to_cell)] -#![feature(const_panic)] -#![feature(const_pin)] -#![feature(const_fn_union)] -#![feature(const_impl_trait)] -#![feature(const_fn_floating_point_arithmetic)] -#![feature(const_fn_fn_ptr_basics)] -#![feature(const_fn_trait_bound)] -#![cfg_attr(bootstrap, feature(const_fn))] +#![feature(const_int_unchecked_arith)] +#![feature(const_intrinsic_copy)] +#![feature(const_intrinsic_forget)] +#![feature(const_likely)] +#![feature(const_maybe_uninit_as_ptr)] +#![feature(const_maybe_uninit_assume_init)] #![feature(const_option)] -#![feature(const_precise_live_drops)] +#![feature(const_pin)] #![feature(const_ptr_offset)] #![feature(const_ptr_offset_from)] #![feature(const_ptr_read)] #![feature(const_ptr_write)] #![feature(const_raw_ptr_comparison)] -#![feature(const_raw_ptr_deref)] +#![feature(const_size_of_val)] #![feature(const_slice_from_raw_parts)] #![feature(const_slice_ptr_len)] -#![feature(const_size_of_val)] #![feature(const_swap)] -#![feature(const_align_of_val)] +#![feature(const_trait_impl)] #![feature(const_type_id)] #![feature(const_type_name)] -#![feature(const_likely)] #![feature(const_unreachable_unchecked)] -#![feature(const_maybe_uninit_assume_init)] -#![feature(const_maybe_uninit_as_ptr)] -#![feature(custom_inner_attributes)] +#![feature(const_default_impls)] +#![feature(duration_consts_2)] +#![feature(ptr_metadata)] +#![feature(slice_ptr_get)] +#![feature(variant_count)] +// +// Language features: +#![feature(abi_unadjusted)] +#![feature(allow_internal_unstable)] +#![feature(asm)] +#![feature(associated_type_bounds)] +#![feature(auto_traits)] +#![feature(cfg_target_has_atomic)] +#![feature(const_fn_floating_point_arithmetic)] +#![feature(const_fn_fn_ptr_basics)] +#![feature(const_fn_trait_bound)] +#![cfg_attr(bootstrap, feature(const_fn_transmute))] +#![cfg_attr(bootstrap, feature(const_fn_union))] +#![feature(const_impl_trait)] +#![feature(const_mut_refs)] +#![feature(const_panic)] +#![feature(const_precise_live_drops)] +#![feature(const_raw_ptr_deref)] +#![feature(const_refs_to_cell)] #![feature(decl_macro)] #![feature(doc_cfg)] #![feature(doc_notable_trait)] -#![feature(duration_consts_2)] -#![cfg_attr(bootstrap, feature(extended_key_value_attributes))] +#![feature(exhaustive_patterns)] #![feature(extern_types)] #![feature(fundamental)] #![feature(intra_doc_pointers)] @@ -119,54 +138,40 @@ #![feature(lang_items)] #![feature(link_llvm_intrinsics)] #![feature(llvm_asm)] +#![feature(min_specialization)] #![feature(negative_impls)] #![feature(never_type)] -#![feature(nll)] -#![feature(exhaustive_patterns)] #![feature(no_core)] -#![feature(auto_traits)] +#![feature(no_coverage)] // rust-lang/rust#84605 +#![feature(no_niche)] // rust-lang/rust#68303 +#![feature(platform_intrinsics)] #![feature(prelude_import)] -#![feature(ptr_metadata)] -#![feature(repr_simd, platform_intrinsics)] +#![feature(repr_simd)] +#![feature(rustc_allow_const_fn_unstable)] #![feature(rustc_attrs)] #![feature(simd_ffi)] -#![feature(min_specialization)] #![feature(staged_api)] -#![feature(std_internals)] #![feature(stmt_expr_attributes)] -#![feature(str_split_as_str)] -#![feature(str_split_inclusive_as_str)] -#![feature(char_indices_offset)] #![feature(trait_alias)] #![feature(transparent_unions)] #![feature(try_blocks)] #![feature(unboxed_closures)] #![feature(unsized_fn_params)] -#![feature(unwind_attributes)] -#![feature(variant_count)] -#![feature(tbm_target_feature)] -#![feature(sse4a_target_feature)] -#![feature(arm_target_feature)] -#![feature(powerpc_target_feature)] -#![feature(mips_target_feature)] +// +// Target features: #![feature(aarch64_target_feature)] -#![feature(wasm_target_feature)] +#![feature(adx_target_feature)] +#![feature(arm_target_feature)] #![feature(avx512_target_feature)] #![feature(cmpxchg16b_target_feature)] -#![feature(rtm_target_feature)] #![feature(f16c_target_feature)] #![feature(hexagon_target_feature)] -#![feature(const_fn_transmute)] -#![feature(abi_unadjusted)] -#![feature(adx_target_feature)] -#![feature(associated_type_bounds)] -#![feature(const_caller_location)] -#![feature(slice_ptr_get)] -#![feature(no_niche)] // rust-lang/rust#68303 -#![feature(no_coverage)] // rust-lang/rust#84605 -#![feature(int_error_matching)] -#![deny(unsafe_op_in_unsafe_fn)] -#![deny(or_patterns_back_compat)] +#![feature(mips_target_feature)] +#![feature(powerpc_target_feature)] +#![feature(rtm_target_feature)] +#![feature(sse4a_target_feature)] +#![feature(tbm_target_feature)] +#![feature(wasm_target_feature)] // allow using `core::` in intra-doc links #[allow(unused_extern_crates)] @@ -180,6 +185,16 @@ use prelude::v1::*; #[macro_use] mod macros; +// We don't export this through #[macro_export] for now, to avoid breakage. +// See https://github.com/rust-lang/rust/issues/82913 +#[cfg(not(test))] +#[unstable(feature = "assert_matches", issue = "82775")] +/// Unstable module containing the unstable `assert_matches` macro. +pub mod assert_matches { + #[unstable(feature = "assert_matches", issue = "82775")] + pub use crate::macros::{assert_matches, debug_assert_matches}; +} + #[macro_use] mod internal_macros; @@ -257,7 +272,6 @@ pub mod option; pub mod panic; pub mod panicking; pub mod pin; -pub mod raw; pub mod result; #[unstable(feature = "async_stream", issue = "79024")] pub mod stream; @@ -308,5 +322,35 @@ pub mod primitive; #[unstable(feature = "stdsimd", issue = "48556")] mod core_arch; +#[doc = include_str!("../../stdarch/crates/core_arch/src/core_arch_docs.md")] #[stable(feature = "simd_arch", since = "1.27.0")] -pub use core_arch::arch; +pub mod arch { + #[stable(feature = "simd_arch", since = "1.27.0")] + pub use crate::core_arch::arch::*; + + /// Inline assembly. + /// + /// Read the [unstable book] for the usage. + /// + /// [unstable book]: ../../unstable-book/library-features/asm.html + #[unstable( + feature = "asm", + issue = "72016", + reason = "inline assembly is not stable enough for use and is subject to change" + )] + #[rustc_builtin_macro] + pub macro asm("assembly template", $(operands,)* $(options($(option),*))?) { + /* compiler built-in */ + } + + /// Module-level inline assembly. + #[unstable( + feature = "global_asm", + issue = "35119", + reason = "`global_asm!` is not stable enough for use and is subject to change" + )] + #[rustc_builtin_macro] + pub macro global_asm("assembly template", $(operands,)* $(options($(option),*))?) { + /* compiler built-in */ + } +} diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs index 7eb65483b99..476f37699ee 100644 --- a/library/core/src/macros/mod.rs +++ b/library/core/src/macros/mod.rs @@ -1,6 +1,6 @@ #[doc = include_str!("panic.md")] #[macro_export] -#[rustc_builtin_macro = "core_panic"] +#[rustc_builtin_macro(core_panic)] #[allow_internal_unstable(edition_panic)] #[stable(feature = "core", since = "1.6.0")] #[rustc_diagnostic_item = "core_panic_macro"] @@ -126,6 +126,8 @@ macro_rules! assert_ne { /// ``` /// #![feature(assert_matches)] /// +/// use std::assert_matches::assert_matches; +/// /// let a = 1u32.checked_add(2); /// let b = 1u32.checked_sub(2); /// assert_matches!(a, Some(_)); @@ -134,11 +136,11 @@ macro_rules! assert_ne { /// let c = Ok("abc".to_string()); /// assert_matches!(c, Ok(x) | Err(x) if x.len() < 100); /// ``` -#[macro_export] #[unstable(feature = "assert_matches", issue = "82775")] #[allow_internal_unstable(core_panic)] -macro_rules! assert_matches { - ($left:expr, $( $pattern:pat_param )|+ $( if $guard: expr )? $(,)?) => ({ +#[rustc_macro_transparency = "semitransparent"] +pub macro assert_matches { + ($left:expr, $(|)? $( $pattern:pat_param )|+ $( if $guard: expr )? $(,)?) => ({ match $left { $( $pattern )|+ $( if $guard )? => {} ref left_val => { @@ -149,8 +151,8 @@ macro_rules! assert_matches { ); } } - }); - ($left:expr, $( $pattern:pat_param )|+ $( if $guard: expr )?, $($arg:tt)+) => ({ + }), + ($left:expr, $(|)? $( $pattern:pat_param )|+ $( if $guard: expr )?, $($arg:tt)+) => ({ match $left { $( $pattern )|+ $( if $guard )? => {} ref left_val => { @@ -161,7 +163,7 @@ macro_rules! assert_matches { ); } } - }); + }), } /// Asserts that a boolean expression is `true` at runtime. @@ -283,6 +285,8 @@ macro_rules! debug_assert_ne { /// ``` /// #![feature(assert_matches)] /// +/// use std::assert_matches::debug_assert_matches; +/// /// let a = 1u32.checked_add(2); /// let b = 1u32.checked_sub(2); /// debug_assert_matches!(a, Some(_)); @@ -294,8 +298,9 @@ macro_rules! debug_assert_ne { #[macro_export] #[unstable(feature = "assert_matches", issue = "82775")] #[allow_internal_unstable(assert_matches)] -macro_rules! debug_assert_matches { - ($($arg:tt)*) => (if $crate::cfg!(debug_assertions) { $crate::assert_matches!($($arg)*); }) +#[rustc_macro_transparency = "semitransparent"] +pub macro debug_assert_matches($($arg:tt)*) { + if $crate::cfg!(debug_assertions) { $crate::assert_matches::assert_matches!($($arg)*); } } /// Returns whether the given expression matches any of the given patterns. @@ -315,7 +320,7 @@ macro_rules! debug_assert_matches { #[macro_export] #[stable(feature = "matches_macro", since = "1.42.0")] macro_rules! matches { - ($expression:expr, $( $pattern:pat_param )|+ $( if $guard: expr )? $(,)?) => { + ($expression:expr, $(|)? $( $pattern:pat_param )|+ $( if $guard: expr )? $(,)?) => { match $expression { $( $pattern )|+ $( if $guard )? => true, _ => false @@ -831,6 +836,31 @@ pub(crate) mod builtin { ($fmt:expr, $($args:tt)*) => {{ /* compiler built-in */ }}; } + /// Same as `format_args`, but can be used in some const contexts. + /// + /// This macro is used by the panic macros for the `const_panic` feature. + /// + /// This macro will be removed once `format_args` is allowed in const contexts. + #[cfg(not(bootstrap))] + #[unstable(feature = "const_format_args", issue = "none")] + #[allow_internal_unstable(fmt_internals, const_fmt_arguments_new)] + #[rustc_builtin_macro] + #[macro_export] + macro_rules! const_format_args { + ($fmt:expr) => {{ /* compiler built-in */ }}; + ($fmt:expr, $($args:tt)*) => {{ /* compiler built-in */ }}; + } + + /// Same as `format_args`, but can be used in some const contexts. + #[cfg(bootstrap)] + #[unstable(feature = "const_format_args", issue = "none")] + #[macro_export] + macro_rules! const_format_args { + ($($t:tt)*) => { + $crate::format_args!($($t)*) + } + } + /// Same as `format_args`, but adds a newline in the end. #[unstable( feature = "format_args_nl", @@ -839,6 +869,7 @@ pub(crate) mod builtin { language use and is subject to change" )] #[allow_internal_unstable(fmt_internals)] + #[doc(hidden)] #[rustc_builtin_macro] #[macro_export] macro_rules! format_args_nl { @@ -1306,27 +1337,6 @@ pub(crate) mod builtin { ($cond:expr, $($arg:tt)+) => {{ /* compiler built-in */ }}; } - /// Inline assembly. - /// - /// Read the [unstable book] for the usage. - /// - /// [unstable book]: ../unstable-book/library-features/asm.html - #[unstable( - feature = "asm", - issue = "72016", - reason = "inline assembly is not stable enough for use and is subject to change" - )] - #[rustc_builtin_macro] - #[macro_export] - macro_rules! asm { - ("assembly template", - $(operands,)* - $(options($(option),*))? - ) => { - /* compiler built-in */ - }; - } - /// LLVM-style inline assembly. /// /// Read the [unstable book] for the usage. @@ -1337,6 +1347,10 @@ pub(crate) mod builtin { issue = "70173", reason = "prefer using the new asm! syntax instead" )] + #[rustc_deprecated( + since = "1.56", + reason = "will be removed from the compiler, use asm! instead" + )] #[rustc_builtin_macro] #[macro_export] macro_rules! llvm_asm { @@ -1349,23 +1363,6 @@ pub(crate) mod builtin { }; } - /// Module-level inline assembly. - #[unstable( - feature = "global_asm", - issue = "35119", - reason = "`global_asm!` is not stable enough for use and is subject to change" - )] - #[rustc_builtin_macro] - #[macro_export] - macro_rules! global_asm { - ("assembly template", - $(operands,)* - $(options($(option),*))? - ) => { - /* compiler built-in */ - }; - } - /// Prints passed tokens into the standard output. #[unstable( feature = "log_syntax", diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs index 2b240455043..333f81ce4cf 100644 --- a/library/core/src/marker.rs +++ b/library/core/src/marker.rs @@ -31,7 +31,6 @@ use crate::hash::Hasher; /// [ub]: ../../reference/behavior-considered-undefined.html #[stable(feature = "rust1", since = "1.0.0")] #[cfg_attr(not(test), rustc_diagnostic_item = "send_trait")] -#[cfg_attr(not(bootstrap), lang = "send")] #[rustc_on_unimplemented( message = "`{Self}` cannot be sent between threads safely", label = "`{Self}` cannot be sent between threads safely" @@ -529,7 +528,8 @@ macro_rules! impls { } #[stable(feature = "rust1", since = "1.0.0")] - impl<T: ?Sized> Default for $t<T> { + #[rustc_const_unstable(feature = "const_default_impls", issue = "87864")] + impl<T: ?Sized> const Default for $t<T> { fn default() -> Self { Self } diff --git a/library/core/src/mem/manually_drop.rs b/library/core/src/mem/manually_drop.rs index 5b99f6954e6..d86939454be 100644 --- a/library/core/src/mem/manually_drop.rs +++ b/library/core/src/mem/manually_drop.rs @@ -44,7 +44,7 @@ use crate::ptr; /// [`MaybeUninit<T>`]: crate::mem::MaybeUninit #[stable(feature = "manually_drop", since = "1.20.0")] #[lang = "manually_drop"] -#[derive(Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] #[repr(transparent)] pub struct ManuallyDrop<T: ?Sized> { value: T, @@ -160,16 +160,3 @@ impl<T: ?Sized> DerefMut for ManuallyDrop<T> { &mut self.value } } - -#[stable(feature = "manually_drop", since = "1.20.0")] -impl<T: Clone> Clone for ManuallyDrop<T> { - #[inline] - fn clone(&self) -> ManuallyDrop<T> { - ManuallyDrop { value: self.value.clone() } - } - - #[inline] - fn clone_from(&mut self, other: &Self) { - self.value.clone_from(&other.value) - } -} diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs index 10219201a40..9c88a623361 100644 --- a/library/core/src/mem/maybe_uninit.rs +++ b/library/core/src/mem/maybe_uninit.rs @@ -79,7 +79,7 @@ use crate::ptr; /// // a `MaybeUninit<T>` may be invalid, and hence this is not UB: /// let mut x = MaybeUninit::<&i32>::uninit(); /// // Set it to a valid value. -/// unsafe { x.as_mut_ptr().write(&0); } +/// x.write(&0); /// // Extract the initialized data -- this is only allowed *after* properly /// // initializing `x`! /// let x = unsafe { x.assume_init() }; @@ -135,7 +135,7 @@ use crate::ptr; /// // this loop, we have a memory leak, but there is no memory safety /// // issue. /// for elem in &mut data[..] { -/// *elem = MaybeUninit::new(vec![42]); +/// elem.write(vec![42]); /// } /// /// // Everything is initialized. Transmute the array to the @@ -161,7 +161,7 @@ use crate::ptr; /// let mut data_len: usize = 0; /// /// for elem in &mut data[0..500] { -/// *elem = MaybeUninit::new(String::from("hello")); +/// elem.write(String::from("hello")); /// data_len += 1; /// } /// @@ -402,12 +402,89 @@ impl<T> MaybeUninit<T> { u } - /// Sets the value of the `MaybeUninit<T>`. This overwrites any previous value - /// without dropping it, so be careful not to use this twice unless you want to - /// skip running the destructor. For your convenience, this also returns a mutable - /// reference to the (now safely initialized) contents of `self`. - #[unstable(feature = "maybe_uninit_extra", issue = "63567")] - #[rustc_const_unstable(feature = "maybe_uninit_extra", issue = "63567")] + /// Sets the value of the `MaybeUninit<T>`. + /// + /// This overwrites any previous value without dropping it, so be careful + /// not to use this twice unless you want to skip running the destructor. + /// For your convenience, this also returns a mutable reference to the + /// (now safely initialized) contents of `self`. + /// + /// As the content is stored inside a `MaybeUninit`, the destructor is not + /// run for the inner data if the MaybeUninit leaves scope without a call to + /// [`assume_init`], [`assume_init_drop`], or similar. Code that receives + /// the mutable reference returned by this function needs to keep this in + /// mind. The safety model of Rust regards leaks as safe, but they are + /// usually still undesirable. This being said, the mutable reference + /// behaves like any other mutable reference would, so assigning a new value + /// to it will drop the old content. + /// + /// [`assume_init`]: Self::assume_init + /// [`assume_init_drop`]: Self::assume_init_drop + /// + /// # Examples + /// + /// Correct usage of this method: + /// + /// ```rust + /// use std::mem::MaybeUninit; + /// + /// let mut x = MaybeUninit::<Vec<u8>>::uninit(); + /// + /// { + /// let hello = x.write((&b"Hello, world!").to_vec()); + /// // Setting hello does not leak prior allocations, but drops them + /// *hello = (&b"Hello").to_vec(); + /// hello[0] = 'h' as u8; + /// } + /// // x is initialized now: + /// let s = unsafe { x.assume_init() }; + /// assert_eq!(b"hello", s.as_slice()); + /// ``` + /// + /// This usage of the method causes a leak: + /// + /// ```rust + /// use std::mem::MaybeUninit; + /// + /// let mut x = MaybeUninit::<String>::uninit(); + /// + /// x.write("Hello".to_string()); + /// // This leaks the contained string: + /// x.write("hello".to_string()); + /// // x is initialized now: + /// let s = unsafe { x.assume_init() }; + /// ``` + /// + /// This method can be used to avoid unsafe in some cases. The example below + /// shows a part of an implementation of a fixed sized arena that lends out + /// pinned references. + /// With `write`, we can avoid the need to write through a raw pointer: + /// + /// ```rust + /// use core::pin::Pin; + /// use core::mem::MaybeUninit; + /// + /// struct PinArena<T> { + /// memory: Box<[MaybeUninit<T>]>, + /// len: usize, + /// } + /// + /// impl <T> PinArena<T> { + /// pub fn capacity(&self) -> usize { + /// self.memory.len() + /// } + /// pub fn push(&mut self, val: T) -> Pin<&mut T> { + /// if self.len >= self.capacity() { + /// panic!("Attempted to push to a full pin arena!"); + /// } + /// let ref_ = self.memory[self.len].write(val); + /// self.len += 1; + /// unsafe { Pin::new_unchecked(ref_) } + /// } + /// } + /// ``` + #[stable(feature = "maybe_uninit_write", since = "1.55.0")] + #[rustc_const_unstable(feature = "const_maybe_uninit_write", issue = "63567")] #[inline(always)] pub const fn write(&mut self, val: T) -> &mut T { *self = MaybeUninit::new(val); @@ -428,7 +505,7 @@ impl<T> MaybeUninit<T> { /// use std::mem::MaybeUninit; /// /// let mut x = MaybeUninit::<Vec<u32>>::uninit(); - /// unsafe { x.as_mut_ptr().write(vec![0, 1, 2]); } + /// x.write(vec![0, 1, 2]); /// // Create a reference into the `MaybeUninit<T>`. This is okay because we initialized it. /// let x_vec = unsafe { &*x.as_ptr() }; /// assert_eq!(x_vec.len(), 3); @@ -465,7 +542,7 @@ impl<T> MaybeUninit<T> { /// use std::mem::MaybeUninit; /// /// let mut x = MaybeUninit::<Vec<u32>>::uninit(); - /// unsafe { x.as_mut_ptr().write(vec![0, 1, 2]); } + /// x.write(vec![0, 1, 2]); /// // Create a reference into the `MaybeUninit<Vec<u32>>`. /// // This is okay because we initialized it. /// let x_vec = unsafe { &mut *x.as_mut_ptr() }; @@ -524,7 +601,7 @@ impl<T> MaybeUninit<T> { /// use std::mem::MaybeUninit; /// /// let mut x = MaybeUninit::<bool>::uninit(); - /// unsafe { x.as_mut_ptr().write(true); } + /// x.write(true); /// let x_init = unsafe { x.assume_init() }; /// assert_eq!(x_init, true); /// ``` @@ -542,6 +619,7 @@ impl<T> MaybeUninit<T> { #[rustc_const_unstable(feature = "const_maybe_uninit_assume_init", issue = "none")] #[inline(always)] #[rustc_diagnostic_item = "assume_init"] + #[track_caller] pub const unsafe fn assume_init(self) -> T { // SAFETY: the caller must guarantee that `self` is initialized. // This also means that `self` must be a `value` variant. @@ -564,9 +642,11 @@ impl<T> MaybeUninit<T> { /// behavior. The [type-level documentation][inv] contains more information about /// this initialization invariant. /// - /// Moreover, this leaves a copy of the same data behind in the `MaybeUninit<T>`. When using - /// multiple copies of the data (by calling `assume_init_read` multiple times, or first - /// calling `assume_init_read` and then [`assume_init`]), it is your responsibility + /// Moreover, similar to the [`ptr::read`] function, this function creates a + /// bitwise copy of the contents, regardless whether the contained type + /// implements the [`Copy`] trait or not. When using multiple copies of the + /// data (by calling `assume_init_read` multiple times, or first calling + /// `assume_init_read` and then [`assume_init`]), it is your responsibility /// to ensure that that data may indeed be duplicated. /// /// [inv]: #initialization-invariant @@ -611,6 +691,7 @@ impl<T> MaybeUninit<T> { #[unstable(feature = "maybe_uninit_extra", issue = "63567")] #[rustc_const_unstable(feature = "maybe_uninit_extra", issue = "63567")] #[inline(always)] + #[track_caller] pub const unsafe fn assume_init_read(&self) -> T { // SAFETY: the caller must guarantee that `self` is initialized. // Reading from `self.as_ptr()` is safe since `self` should be initialized. @@ -622,7 +703,8 @@ impl<T> MaybeUninit<T> { /// Drops the contained value in place. /// - /// If you have ownership of the `MaybeUninit`, you can use [`assume_init`] instead. + /// If you have ownership of the `MaybeUninit`, you can also use + /// [`assume_init`] as an alternative. /// /// # Safety /// @@ -632,11 +714,12 @@ impl<T> MaybeUninit<T> { /// /// On top of that, all additional invariants of the type `T` must be /// satisfied, as the `Drop` implementation of `T` (or its members) may - /// rely on this. For example, a `1`-initialized [`Vec<T>`] is considered - /// initialized (under the current implementation; this does not constitute - /// a stable guarantee) because the only requirement the compiler knows - /// about it is that the data pointer must be non-null. Dropping such a - /// `Vec<T>` however will cause undefined behaviour. + /// rely on this. For example, setting a [`Vec<T>`] to an invalid but + /// non-null address makes it initialized (under the current implementation; + /// this does not constitute a stable guarantee), because the only + /// requirement the compiler knows about it is that the data pointer must be + /// non-null. Dropping such a `Vec<T>` however will cause undefined + /// behaviour. /// /// [`assume_init`]: MaybeUninit::assume_init /// [`Vec<T>`]: ../../std/vec/struct.Vec.html @@ -665,12 +748,11 @@ impl<T> MaybeUninit<T> { /// ### Correct usage of this method: /// /// ```rust - /// #![feature(maybe_uninit_ref)] /// use std::mem::MaybeUninit; /// /// let mut x = MaybeUninit::<Vec<u32>>::uninit(); /// // Initialize `x`: - /// unsafe { x.as_mut_ptr().write(vec![1, 2, 3]); } + /// x.write(vec![1, 2, 3]); /// // Now that our `MaybeUninit<_>` is known to be initialized, it is okay to /// // create a shared reference to it: /// let x: &Vec<u32> = unsafe { @@ -683,7 +765,6 @@ impl<T> MaybeUninit<T> { /// ### *Incorrect* usages of this method: /// /// ```rust,no_run - /// #![feature(maybe_uninit_ref)] /// use std::mem::MaybeUninit; /// /// let x = MaybeUninit::<Vec<u32>>::uninit(); @@ -692,7 +773,6 @@ impl<T> MaybeUninit<T> { /// ``` /// /// ```rust,no_run - /// #![feature(maybe_uninit_ref)] /// use std::{cell::Cell, mem::MaybeUninit}; /// /// let b = MaybeUninit::<Cell<bool>>::uninit(); @@ -703,7 +783,7 @@ impl<T> MaybeUninit<T> { /// // Reference to an uninitialized `Cell<bool>`: UB! /// } /// ``` - #[unstable(feature = "maybe_uninit_ref", issue = "63568")] + #[stable(feature = "maybe_uninit_ref", since = "1.55.0")] #[rustc_const_unstable(feature = "const_maybe_uninit_assume_init", issue = "none")] #[inline(always)] pub const unsafe fn assume_init_ref(&self) -> &T { @@ -733,7 +813,6 @@ impl<T> MaybeUninit<T> { /// ### Correct usage of this method: /// /// ```rust - /// #![feature(maybe_uninit_ref)] /// use std::mem::MaybeUninit; /// /// # unsafe extern "C" fn initialize_buffer(buf: *mut [u8; 1024]) { *buf = [0; 1024] } @@ -769,7 +848,6 @@ impl<T> MaybeUninit<T> { /// You cannot use `.assume_init_mut()` to initialize a value: /// /// ```rust,no_run - /// #![feature(maybe_uninit_ref)] /// use std::mem::MaybeUninit; /// /// let mut b = MaybeUninit::<bool>::uninit(); @@ -785,7 +863,6 @@ impl<T> MaybeUninit<T> { /// [`Read`]: https://doc.rust-lang.org/std/io/trait.Read.html /// /// ```rust,no_run - /// #![feature(maybe_uninit_ref)] /// use std::{io, mem::MaybeUninit}; /// /// fn read_chunk (reader: &'_ mut dyn io::Read) -> io::Result<[u8; 64]> @@ -802,7 +879,6 @@ impl<T> MaybeUninit<T> { /// Nor can you use direct field access to do field-by-field gradual initialization: /// /// ```rust,no_run - /// #![feature(maybe_uninit_ref)] /// use std::{mem::MaybeUninit, ptr}; /// /// struct Foo { @@ -823,10 +899,7 @@ impl<T> MaybeUninit<T> { /// foo.assume_init() /// }; /// ``` - // FIXME(#76092): We currently rely on the above being incorrect, i.e., we have references - // to uninitialized data (e.g., in `libcore/fmt/float.rs`). We should make - // a final decision about the rules before stabilization. - #[unstable(feature = "maybe_uninit_ref", issue = "63568")] + #[stable(feature = "maybe_uninit_ref", since = "1.55.0")] #[rustc_const_unstable(feature = "const_maybe_uninit_assume_init", issue = "none")] #[inline(always)] pub const unsafe fn assume_init_mut(&mut self) -> &mut T { @@ -853,9 +926,9 @@ impl<T> MaybeUninit<T> { /// use std::mem::MaybeUninit; /// /// let mut array: [MaybeUninit<i32>; 3] = MaybeUninit::uninit_array(); - /// array[0] = MaybeUninit::new(0); - /// array[1] = MaybeUninit::new(1); - /// array[2] = MaybeUninit::new(2); + /// array[0].write(0); + /// array[1].write(1); + /// array[2].write(2); /// /// // SAFETY: Now safe as we initialised all elements /// let array = unsafe { @@ -866,6 +939,7 @@ impl<T> MaybeUninit<T> { /// ``` #[unstable(feature = "maybe_uninit_array_assume_init", issue = "80908")] #[inline(always)] + #[track_caller] pub unsafe fn array_assume_init<const N: usize>(array: [Self; N]) -> [T; N] { // SAFETY: // * The caller guarantees that all elements of the array are initialized @@ -936,7 +1010,7 @@ impl<T> MaybeUninit<T> { this.as_mut_ptr() as *mut T } - /// Copies the elements from `src` to `this`, returning a mutable reference to the now initalized contents of `this`. + /// Copies the elements from `src` to `this`, returning a mutable reference to the now initialized contents of `this`. /// /// If `T` does not implement `Copy`, use [`write_slice_cloned`] /// @@ -989,12 +1063,12 @@ impl<T> MaybeUninit<T> { this.copy_from_slice(uninit_src); - // SAFETY: Valid elements have just been copied into `this` so it is initalized + // SAFETY: Valid elements have just been copied into `this` so it is initialized unsafe { MaybeUninit::slice_assume_init_mut(this) } } - /// Clones the elements from `src` to `this`, returning a mutable reference to the now initalized contents of `this`. - /// Any already initalized elements will not be dropped. + /// Clones the elements from `src` to `this`, returning a mutable reference to the now initialized contents of `this`. + /// Any already initialized elements will not be dropped. /// /// If `T` implements `Copy`, use [`write_slice`] /// @@ -1080,7 +1154,7 @@ impl<T> MaybeUninit<T> { super::forget(guard); - // SAFETY: Valid elements have just been written into `this` so it is initalized + // SAFETY: Valid elements have just been written into `this` so it is initialized unsafe { MaybeUninit::slice_assume_init_mut(this) } } } diff --git a/library/core/src/mem/mod.rs b/library/core/src/mem/mod.rs index 5bf47c3951d..d6eb535fd2e 100644 --- a/library/core/src/mem/mod.rs +++ b/library/core/src/mem/mod.rs @@ -140,6 +140,7 @@ pub use crate::intrinsics::transmute; #[inline] #[rustc_const_stable(feature = "const_forget", since = "1.46.0")] #[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr(not(test), rustc_diagnostic_item = "mem_forget")] pub const fn forget<T>(t: T) { let _ = ManuallyDrop::new(t); } @@ -298,6 +299,7 @@ pub fn forget_unsized<T: ?Sized>(t: T) { #[stable(feature = "rust1", since = "1.0.0")] #[rustc_promotable] #[rustc_const_stable(feature = "const_size_of", since = "1.24.0")] +#[cfg_attr(not(test), rustc_diagnostic_item = "mem_size_of")] pub const fn size_of<T>() -> usize { intrinsics::size_of::<T>() } @@ -324,6 +326,7 @@ pub const fn size_of<T>() -> usize { #[inline] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_unstable(feature = "const_size_of_val", issue = "46571")] +#[cfg_attr(not(test), rustc_diagnostic_item = "mem_size_of_val")] pub const fn size_of_val<T: ?Sized>(val: &T) -> usize { // SAFETY: `val` is a reference, so it's a valid raw pointer unsafe { intrinsics::size_of_val(val) } @@ -619,6 +622,7 @@ pub const fn needs_drop<T>() -> bool { #[allow(deprecated_in_future)] #[allow(deprecated)] #[rustc_diagnostic_item = "mem_zeroed"] +#[track_caller] pub unsafe fn zeroed<T>() -> T { // SAFETY: the caller must guarantee that an all-zero value is valid for `T`. unsafe { @@ -654,6 +658,7 @@ pub unsafe fn zeroed<T>() -> T { #[allow(deprecated_in_future)] #[allow(deprecated)] #[rustc_diagnostic_item = "mem_uninitialized"] +#[track_caller] pub unsafe fn uninitialized<T>() -> T { // SAFETY: the caller must guarantee that an unitialized value is valid for `T`. unsafe { @@ -814,6 +819,7 @@ pub fn take<T: Default>(dest: &mut T) -> T { #[stable(feature = "rust1", since = "1.0.0")] #[must_use = "if you don't need the old value, you can just assign the new value directly"] #[rustc_const_unstable(feature = "const_replace", issue = "83164")] +#[cfg_attr(not(test), rustc_diagnostic_item = "mem_replace")] pub const fn replace<T>(dest: &mut T, src: T) -> T { // SAFETY: We read from `dest` but directly write `src` into it afterwards, // such that the old value is not duplicated. Nothing is dropped and @@ -888,6 +894,7 @@ pub const fn replace<T>(dest: &mut T, src: T) -> T { /// [`RefCell`]: crate::cell::RefCell #[inline] #[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr(not(test), rustc_diagnostic_item = "mem_drop")] pub fn drop<T>(_x: T) {} /// Interprets `src` as having type `&U`, and then reads `src` without moving @@ -934,7 +941,7 @@ pub fn drop<T>(_x: T) {} #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_unstable(feature = "const_transmute_copy", issue = "83165")] pub const unsafe fn transmute_copy<T, U>(src: &T) -> U { - // If U has a higher alignment requirement, src may not be suitably aligned. + // If U has a higher alignment requirement, src might not be suitably aligned. if align_of::<U>() > align_of::<T>() { // SAFETY: `src` is a reference which is guaranteed to be valid for reads. // The caller must guarantee that the actual transmutation is safe. @@ -1015,6 +1022,7 @@ impl<T> fmt::Debug for Discriminant<T> { /// ``` #[stable(feature = "discriminant_value", since = "1.21.0")] #[rustc_const_unstable(feature = "const_discriminant", issue = "69821")] +#[cfg_attr(not(test), rustc_diagnostic_item = "mem_discriminant")] pub const fn discriminant<T>(v: &T) -> Discriminant<T> { Discriminant(intrinsics::discriminant_value(v)) } diff --git a/library/core/src/num/dec2flt/algorithm.rs b/library/core/src/num/dec2flt/algorithm.rs deleted file mode 100644 index 313b6870ac9..00000000000 --- a/library/core/src/num/dec2flt/algorithm.rs +++ /dev/null @@ -1,429 +0,0 @@ -//! The various algorithms from the paper. - -use crate::cmp::min; -use crate::cmp::Ordering::{Equal, Greater, Less}; -use crate::num::dec2flt::num::{self, Big}; -use crate::num::dec2flt::rawfp::{self, fp_to_float, next_float, prev_float, RawFloat, Unpacked}; -use crate::num::dec2flt::table; -use crate::num::diy_float::Fp; - -/// Number of significand bits in Fp -const P: u32 = 64; - -// We simply store the best approximation for *all* exponents, so the variable "h" and the -// associated conditions can be omitted. This trades performance for a couple kilobytes of space. - -fn power_of_ten(e: i16) -> Fp { - assert!(e >= table::MIN_E); - let i = e - table::MIN_E; - let sig = table::POWERS.0[i as usize]; - let exp = table::POWERS.1[i as usize]; - Fp { f: sig, e: exp } -} - -// In most architectures, floating point operations have an explicit bit size, therefore the -// precision of the computation is determined on a per-operation basis. -#[cfg(any(not(target_arch = "x86"), target_feature = "sse2"))] -mod fpu_precision { - pub fn set_precision<T>() {} -} - -// On x86, the x87 FPU is used for float operations if the SSE/SSE2 extensions are not available. -// The x87 FPU operates with 80 bits of precision by default, which means that operations will -// round to 80 bits causing double rounding to happen when values are eventually represented as -// 32/64 bit float values. To overcome this, the FPU control word can be set so that the -// computations are performed in the desired precision. -#[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] -mod fpu_precision { - use crate::mem::size_of; - - /// A structure used to preserve the original value of the FPU control word, so that it can be - /// restored when the structure is dropped. - /// - /// The x87 FPU is a 16-bits register whose fields are as follows: - /// - /// | 12-15 | 10-11 | 8-9 | 6-7 | 5 | 4 | 3 | 2 | 1 | 0 | - /// |------:|------:|----:|----:|---:|---:|---:|---:|---:|---:| - /// | | RC | PC | | PM | UM | OM | ZM | DM | IM | - /// - /// The documentation for all of the fields is available in the IA-32 Architectures Software - /// Developer's Manual (Volume 1). - /// - /// The only field which is relevant for the following code is PC, Precision Control. This - /// field determines the precision of the operations performed by the FPU. It can be set to: - /// - 0b00, single precision i.e., 32-bits - /// - 0b10, double precision i.e., 64-bits - /// - 0b11, double extended precision i.e., 80-bits (default state) - /// The 0b01 value is reserved and should not be used. - pub struct FPUControlWord(u16); - - fn set_cw(cw: u16) { - // SAFETY: the `fldcw` instruction has been audited to be able to work correctly with - // any `u16` - unsafe { - asm!( - "fldcw word ptr [{}]", - in(reg) &cw, - options(nostack), - ) - } - } - - /// Sets the precision field of the FPU to `T` and returns a `FPUControlWord`. - pub fn set_precision<T>() -> FPUControlWord { - let mut cw = 0_u16; - - // Compute the value for the Precision Control field that is appropriate for `T`. - let cw_precision = match size_of::<T>() { - 4 => 0x0000, // 32 bits - 8 => 0x0200, // 64 bits - _ => 0x0300, // default, 80 bits - }; - - // Get the original value of the control word to restore it later, when the - // `FPUControlWord` structure is dropped - // SAFETY: the `fnstcw` instruction has been audited to be able to work correctly with - // any `u16` - unsafe { - asm!( - "fnstcw word ptr [{}]", - in(reg) &mut cw, - options(nostack), - ) - } - - // Set the control word to the desired precision. This is achieved by masking away the old - // precision (bits 8 and 9, 0x300) and replacing it with the precision flag computed above. - set_cw((cw & 0xFCFF) | cw_precision); - - FPUControlWord(cw) - } - - impl Drop for FPUControlWord { - fn drop(&mut self) { - set_cw(self.0) - } - } -} - -/// The fast path of Bellerophon using machine-sized integers and floats. -/// -/// This is extracted into a separate function so that it can be attempted before constructing -/// a bignum. -pub fn fast_path<T: RawFloat>(integral: &[u8], fractional: &[u8], e: i64) -> Option<T> { - let num_digits = integral.len() + fractional.len(); - // log_10(f64::MAX_SIG) ~ 15.95. We compare the exact value to MAX_SIG near the end, - // this is just a quick, cheap rejection (and also frees the rest of the code from - // worrying about underflow). - if num_digits > 16 { - return None; - } - if e.abs() >= T::CEIL_LOG5_OF_MAX_SIG as i64 { - return None; - } - let f = num::from_str_unchecked(integral.iter().chain(fractional.iter())); - if f > T::MAX_SIG { - return None; - } - - // The fast path crucially depends on arithmetic being rounded to the correct number of bits - // without any intermediate rounding. On x86 (without SSE or SSE2) this requires the precision - // of the x87 FPU stack to be changed so that it directly rounds to 64/32 bit. - // The `set_precision` function takes care of setting the precision on architectures which - // require setting it by changing the global state (like the control word of the x87 FPU). - let _cw = fpu_precision::set_precision::<T>(); - - // The case e < 0 cannot be folded into the other branch. Negative powers result in - // a repeating fractional part in binary, which are rounded, which causes real - // (and occasionally quite significant!) errors in the final result. - if e >= 0 { - Some(T::from_int(f) * T::short_fast_pow10(e as usize)) - } else { - Some(T::from_int(f) / T::short_fast_pow10(e.abs() as usize)) - } -} - -/// Algorithm Bellerophon is trivial code justified by non-trivial numeric analysis. -/// -/// It rounds ``f`` to a float with 64 bit significand and multiplies it by the best approximation -/// of `10^e` (in the same floating point format). This is often enough to get the correct result. -/// However, when the result is close to halfway between two adjacent (ordinary) floats, the -/// compound rounding error from multiplying two approximation means the result may be off by a -/// few bits. When this happens, the iterative Algorithm R fixes things up. -/// -/// The hand-wavy "close to halfway" is made precise by the numeric analysis in the paper. -/// In the words of Clinger: -/// -/// > Slop, expressed in units of the least significant bit, is an inclusive bound for the error -/// > accumulated during the floating point calculation of the approximation to f * 10^e. (Slop is -/// > not a bound for the true error, but bounds the difference between the approximation z and -/// > the best possible approximation that uses p bits of significand.) -pub fn bellerophon<T: RawFloat>(f: &Big, e: i16) -> T { - let slop = if f <= &Big::from_u64(T::MAX_SIG) { - // The cases abs(e) < log5(2^N) are in fast_path() - if e >= 0 { 0 } else { 3 } - } else { - if e >= 0 { 1 } else { 4 } - }; - let z = rawfp::big_to_fp(f).mul(&power_of_ten(e)).normalize(); - let exp_p_n = 1 << (P - T::SIG_BITS as u32); - let lowbits: i64 = (z.f % exp_p_n) as i64; - // Is the slop large enough to make a difference when - // rounding to n bits? - if (lowbits - exp_p_n as i64 / 2).abs() <= slop { - algorithm_r(f, e, fp_to_float(z)) - } else { - fp_to_float(z) - } -} - -/// An iterative algorithm that improves a floating point approximation of `f * 10^e`. -/// -/// Each iteration gets one unit in the last place closer, which of course takes terribly long to -/// converge if `z0` is even mildly off. Luckily, when used as fallback for Bellerophon, the -/// starting approximation is off by at most one ULP. -fn algorithm_r<T: RawFloat>(f: &Big, e: i16, z0: T) -> T { - let mut z = z0; - loop { - let raw = z.unpack(); - let (m, k) = (raw.sig, raw.k); - let mut x = f.clone(); - let mut y = Big::from_u64(m); - - // Find positive integers `x`, `y` such that `x / y` is exactly `(f * 10^e) / (m * 2^k)`. - // This not only avoids dealing with the signs of `e` and `k`, we also eliminate the - // power of two common to `10^e` and `2^k` to make the numbers smaller. - make_ratio(&mut x, &mut y, e, k); - - let m_digits = [(m & 0xFF_FF_FF_FF) as u32, (m >> 32) as u32]; - // This is written a bit awkwardly because our bignums don't support - // negative numbers, so we use the absolute value + sign information. - // The multiplication with m_digits can't overflow. If `x` or `y` are large enough that - // we need to worry about overflow, then they are also large enough that `make_ratio` has - // reduced the fraction by a factor of 2^64 or more. - let (d2, d_negative) = if x >= y { - // Don't need x any more, save a clone(). - x.sub(&y).mul_pow2(1).mul_digits(&m_digits); - (x, false) - } else { - // Still need y - make a copy. - let mut y = y.clone(); - y.sub(&x).mul_pow2(1).mul_digits(&m_digits); - (y, true) - }; - - if d2 < y { - let mut d2_double = d2; - d2_double.mul_pow2(1); - if m == T::MIN_SIG && d_negative && d2_double > y { - z = prev_float(z); - } else { - return z; - } - } else if d2 == y { - if m % 2 == 0 { - if m == T::MIN_SIG && d_negative { - z = prev_float(z); - } else { - return z; - } - } else if d_negative { - z = prev_float(z); - } else { - z = next_float(z); - } - } else if d_negative { - z = prev_float(z); - } else { - z = next_float(z); - } - } -} - -/// Given `x = f` and `y = m` where `f` represent input decimal digits as usual and `m` is the -/// significand of a floating point approximation, make the ratio `x / y` equal to -/// `(f * 10^e) / (m * 2^k)`, possibly reduced by a power of two both have in common. -fn make_ratio(x: &mut Big, y: &mut Big, e: i16, k: i16) { - let (e_abs, k_abs) = (e.abs() as usize, k.abs() as usize); - if e >= 0 { - if k >= 0 { - // x = f * 10^e, y = m * 2^k, except that we reduce the fraction by some power of two. - let common = min(e_abs, k_abs); - x.mul_pow5(e_abs).mul_pow2(e_abs - common); - y.mul_pow2(k_abs - common); - } else { - // x = f * 10^e * 2^abs(k), y = m - // This can't overflow because it requires positive `e` and negative `k`, which can - // only happen for values extremely close to 1, which means that `e` and `k` will be - // comparatively tiny. - x.mul_pow5(e_abs).mul_pow2(e_abs + k_abs); - } - } else { - if k >= 0 { - // x = f, y = m * 10^abs(e) * 2^k - // This can't overflow either, see above. - y.mul_pow5(e_abs).mul_pow2(k_abs + e_abs); - } else { - // x = f * 2^abs(k), y = m * 10^abs(e), again reducing by a common power of two. - let common = min(e_abs, k_abs); - x.mul_pow2(k_abs - common); - y.mul_pow5(e_abs).mul_pow2(e_abs - common); - } - } -} - -/// Conceptually, Algorithm M is the simplest way to convert a decimal to a float. -/// -/// We form a ratio that is equal to `f * 10^e`, then throwing in powers of two until it gives -/// a valid float significand. The binary exponent `k` is the number of times we multiplied -/// numerator or denominator by two, i.e., at all times `f * 10^e` equals `(u / v) * 2^k`. -/// When we have found out significand, we only need to round by inspecting the remainder of the -/// division, which is done in helper functions further below. -/// -/// This algorithm is super slow, even with the optimization described in `quick_start()`. -/// However, it's the simplest of the algorithms to adapt for overflow, underflow, and subnormal -/// results. This implementation takes over when Bellerophon and Algorithm R are overwhelmed. -/// Detecting underflow and overflow is easy: The ratio still isn't an in-range significand, -/// yet the minimum/maximum exponent has been reached. In the case of overflow, we simply return -/// infinity. -/// -/// Handling underflow and subnormals is trickier. One big problem is that, with the minimum -/// exponent, the ratio might still be too large for a significand. See underflow() for details. -pub fn algorithm_m<T: RawFloat>(f: &Big, e: i16) -> T { - let mut u; - let mut v; - let e_abs = e.abs() as usize; - let mut k = 0; - if e < 0 { - u = f.clone(); - v = Big::from_small(1); - v.mul_pow5(e_abs).mul_pow2(e_abs); - } else { - // FIXME possible optimization: generalize big_to_fp so that we can do the equivalent of - // fp_to_float(big_to_fp(u)) here, only without the double rounding. - u = f.clone(); - u.mul_pow5(e_abs).mul_pow2(e_abs); - v = Big::from_small(1); - } - quick_start::<T>(&mut u, &mut v, &mut k); - let mut rem = Big::from_small(0); - let mut x = Big::from_small(0); - let min_sig = Big::from_u64(T::MIN_SIG); - let max_sig = Big::from_u64(T::MAX_SIG); - loop { - u.div_rem(&v, &mut x, &mut rem); - if k == T::MIN_EXP_INT { - // We have to stop at the minimum exponent, if we wait until `k < T::MIN_EXP_INT`, - // then we'd be off by a factor of two. Unfortunately this means we have to special- - // case normal numbers with the minimum exponent. - // FIXME find a more elegant formulation, but run the `tiny-pow10` test to make sure - // that it's actually correct! - if x >= min_sig && x <= max_sig { - break; - } - return underflow(x, v, rem); - } - if k > T::MAX_EXP_INT { - return T::INFINITY; - } - if x < min_sig { - u.mul_pow2(1); - k -= 1; - } else if x > max_sig { - v.mul_pow2(1); - k += 1; - } else { - break; - } - } - let q = num::to_u64(&x); - let z = rawfp::encode_normal(Unpacked::new(q, k)); - round_by_remainder(v, rem, q, z) -} - -/// Skips over most Algorithm M iterations by checking the bit length. -fn quick_start<T: RawFloat>(u: &mut Big, v: &mut Big, k: &mut i16) { - // The bit length is an estimate of the base two logarithm, and log(u / v) = log(u) - log(v). - // The estimate is off by at most 1, but always an under-estimate, so the error on log(u) - // and log(v) are of the same sign and cancel out (if both are large). Therefore the error - // for log(u / v) is at most one as well. - // The target ratio is one where u/v is in an in-range significand. Thus our termination - // condition is log2(u / v) being the significand bits, plus/minus one. - // FIXME Looking at the second bit could improve the estimate and avoid some more divisions. - let target_ratio = T::SIG_BITS as i16; - let log2_u = u.bit_length() as i16; - let log2_v = v.bit_length() as i16; - let mut u_shift: i16 = 0; - let mut v_shift: i16 = 0; - assert!(*k == 0); - loop { - if *k == T::MIN_EXP_INT { - // Underflow or subnormal. Leave it to the main function. - break; - } - if *k == T::MAX_EXP_INT { - // Overflow. Leave it to the main function. - break; - } - let log2_ratio = (log2_u + u_shift) - (log2_v + v_shift); - if log2_ratio < target_ratio - 1 { - u_shift += 1; - *k -= 1; - } else if log2_ratio > target_ratio + 1 { - v_shift += 1; - *k += 1; - } else { - break; - } - } - u.mul_pow2(u_shift as usize); - v.mul_pow2(v_shift as usize); -} - -fn underflow<T: RawFloat>(x: Big, v: Big, rem: Big) -> T { - if x < Big::from_u64(T::MIN_SIG) { - let q = num::to_u64(&x); - let z = rawfp::encode_subnormal(q); - return round_by_remainder(v, rem, q, z); - } - // Ratio isn't an in-range significand with the minimum exponent, so we need to round off - // excess bits and adjust the exponent accordingly. The real value now looks like this: - // - // x lsb - // /--------------\/ - // 1010101010101010.10101010101010 * 2^k - // \-----/\-------/ \------------/ - // q trunc. (represented by rem) - // - // Therefore, when the rounded-off bits are != 0.5 ULP, they decide the rounding - // on their own. When they are equal and the remainder is non-zero, the value still - // needs to be rounded up. Only when the rounded off bits are 1/2 and the remainder - // is zero, we have a half-to-even situation. - let bits = x.bit_length(); - let lsb = bits - T::SIG_BITS as usize; - let q = num::get_bits(&x, lsb, bits); - let k = T::MIN_EXP_INT + lsb as i16; - let z = rawfp::encode_normal(Unpacked::new(q, k)); - let q_even = q % 2 == 0; - match num::compare_with_half_ulp(&x, lsb) { - Greater => next_float(z), - Less => z, - Equal if rem.is_zero() && q_even => z, - Equal => next_float(z), - } -} - -/// Ordinary round-to-even, obfuscated by having to round based on the remainder of a division. -fn round_by_remainder<T: RawFloat>(v: Big, r: Big, q: u64, z: T) -> T { - let mut v_minus_r = v; - v_minus_r.sub(&r); - if r < v_minus_r { - z - } else if r > v_minus_r { - next_float(z) - } else if q % 2 == 0 { - z - } else { - next_float(z) - } -} diff --git a/library/core/src/num/dec2flt/common.rs b/library/core/src/num/dec2flt/common.rs new file mode 100644 index 00000000000..247123737df --- /dev/null +++ b/library/core/src/num/dec2flt/common.rs @@ -0,0 +1,198 @@ +//! Common utilities, for internal use only. + +use crate::ptr; + +/// Helper methods to process immutable bytes. +pub(crate) trait ByteSlice: AsRef<[u8]> { + unsafe fn first_unchecked(&self) -> u8 { + debug_assert!(!self.is_empty()); + // SAFETY: safe as long as self is not empty + unsafe { *self.as_ref().get_unchecked(0) } + } + + /// Get if the slice contains no elements. + fn is_empty(&self) -> bool { + self.as_ref().is_empty() + } + + /// Check if the slice at least `n` length. + fn check_len(&self, n: usize) -> bool { + n <= self.as_ref().len() + } + + /// Check if the first character in the slice is equal to c. + fn first_is(&self, c: u8) -> bool { + self.as_ref().first() == Some(&c) + } + + /// Check if the first character in the slice is equal to c1 or c2. + fn first_is2(&self, c1: u8, c2: u8) -> bool { + if let Some(&c) = self.as_ref().first() { c == c1 || c == c2 } else { false } + } + + /// Bounds-checked test if the first character in the slice is a digit. + fn first_isdigit(&self) -> bool { + if let Some(&c) = self.as_ref().first() { c.is_ascii_digit() } else { false } + } + + /// Check if self starts with u with a case-insensitive comparison. + fn eq_ignore_case(&self, u: &[u8]) -> bool { + debug_assert!(self.as_ref().len() >= u.len()); + let iter = self.as_ref().iter().zip(u.iter()); + let d = iter.fold(0, |i, (&x, &y)| i | (x ^ y)); + d == 0 || d == 32 + } + + /// Get the remaining slice after the first N elements. + fn advance(&self, n: usize) -> &[u8] { + &self.as_ref()[n..] + } + + /// Get the slice after skipping all leading characters equal c. + fn skip_chars(&self, c: u8) -> &[u8] { + let mut s = self.as_ref(); + while s.first_is(c) { + s = s.advance(1); + } + s + } + + /// Get the slice after skipping all leading characters equal c1 or c2. + fn skip_chars2(&self, c1: u8, c2: u8) -> &[u8] { + let mut s = self.as_ref(); + while s.first_is2(c1, c2) { + s = s.advance(1); + } + s + } + + /// Read 8 bytes as a 64-bit integer in little-endian order. + unsafe fn read_u64_unchecked(&self) -> u64 { + debug_assert!(self.check_len(8)); + let src = self.as_ref().as_ptr() as *const u64; + // SAFETY: safe as long as self is at least 8 bytes + u64::from_le(unsafe { ptr::read_unaligned(src) }) + } + + /// Try to read the next 8 bytes from the slice. + fn read_u64(&self) -> Option<u64> { + if self.check_len(8) { + // SAFETY: self must be at least 8 bytes. + Some(unsafe { self.read_u64_unchecked() }) + } else { + None + } + } + + /// Calculate the offset of slice from another. + fn offset_from(&self, other: &Self) -> isize { + other.as_ref().len() as isize - self.as_ref().len() as isize + } +} + +impl ByteSlice for [u8] {} + +/// Helper methods to process mutable bytes. +pub(crate) trait ByteSliceMut: AsMut<[u8]> { + /// Write a 64-bit integer as 8 bytes in little-endian order. + unsafe fn write_u64_unchecked(&mut self, value: u64) { + debug_assert!(self.as_mut().len() >= 8); + let dst = self.as_mut().as_mut_ptr() as *mut u64; + // NOTE: we must use `write_unaligned`, since dst is not + // guaranteed to be properly aligned. Miri will warn us + // if we use `write` instead of `write_unaligned`, as expected. + // SAFETY: safe as long as self is at least 8 bytes + unsafe { + ptr::write_unaligned(dst, u64::to_le(value)); + } + } +} + +impl ByteSliceMut for [u8] {} + +/// Bytes wrapper with specialized methods for ASCII characters. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub(crate) struct AsciiStr<'a> { + slc: &'a [u8], +} + +impl<'a> AsciiStr<'a> { + pub fn new(slc: &'a [u8]) -> Self { + Self { slc } + } + + /// Advance the view by n, advancing it in-place to (n..). + pub unsafe fn step_by(&mut self, n: usize) -> &mut Self { + // SAFETY: safe as long n is less than the buffer length + self.slc = unsafe { self.slc.get_unchecked(n..) }; + self + } + + /// Advance the view by n, advancing it in-place to (1..). + pub unsafe fn step(&mut self) -> &mut Self { + // SAFETY: safe as long as self is not empty + unsafe { self.step_by(1) } + } + + /// Iteratively parse and consume digits from bytes. + pub fn parse_digits(&mut self, mut func: impl FnMut(u8)) { + while let Some(&c) = self.as_ref().first() { + let c = c.wrapping_sub(b'0'); + if c < 10 { + func(c); + // SAFETY: self cannot be empty + unsafe { + self.step(); + } + } else { + break; + } + } + } +} + +impl<'a> AsRef<[u8]> for AsciiStr<'a> { + #[inline] + fn as_ref(&self) -> &[u8] { + self.slc + } +} + +impl<'a> ByteSlice for AsciiStr<'a> {} + +/// Determine if 8 bytes are all decimal digits. +/// This does not care about the order in which the bytes were loaded. +pub(crate) fn is_8digits(v: u64) -> bool { + let a = v.wrapping_add(0x4646_4646_4646_4646); + let b = v.wrapping_sub(0x3030_3030_3030_3030); + (a | b) & 0x8080_8080_8080_8080 == 0 +} + +/// Iteratively parse and consume digits from bytes. +pub(crate) fn parse_digits(s: &mut &[u8], mut f: impl FnMut(u8)) { + while let Some(&c) = s.get(0) { + let c = c.wrapping_sub(b'0'); + if c < 10 { + f(c); + *s = s.advance(1); + } else { + break; + } + } +} + +/// A custom 64-bit floating point type, representing `f * 2^e`. +/// e is biased, so it be directly shifted into the exponent bits. +#[derive(Debug, Copy, Clone, PartialEq, Eq, Default)] +pub struct BiasedFp { + /// The significant digits. + pub f: u64, + /// The biased, binary exponent. + pub e: i32, +} + +impl BiasedFp { + pub const fn zero_pow2(e: i32) -> Self { + Self { f: 0, e } + } +} diff --git a/library/core/src/num/dec2flt/decimal.rs b/library/core/src/num/dec2flt/decimal.rs new file mode 100644 index 00000000000..f8edc3625e0 --- /dev/null +++ b/library/core/src/num/dec2flt/decimal.rs @@ -0,0 +1,351 @@ +//! Arbitrary-precision decimal class for fallback algorithms. +//! +//! This is only used if the fast-path (native floats) and +//! the Eisel-Lemire algorithm are unable to unambiguously +//! determine the float. +//! +//! The technique used is "Simple Decimal Conversion", developed +//! by Nigel Tao and Ken Thompson. A detailed description of the +//! algorithm can be found in "ParseNumberF64 by Simple Decimal Conversion", +//! available online: <https://nigeltao.github.io/blog/2020/parse-number-f64-simple.html>. + +use crate::num::dec2flt::common::{is_8digits, parse_digits, ByteSlice, ByteSliceMut}; + +#[derive(Clone)] +pub struct Decimal { + /// The number of significant digits in the decimal. + pub num_digits: usize, + /// The offset of the decimal point in the significant digits. + pub decimal_point: i32, + /// If the number of significant digits stored in the decimal is truncated. + pub truncated: bool, + /// Buffer of the raw digits, in the range [0, 9]. + pub digits: [u8; Self::MAX_DIGITS], +} + +impl Default for Decimal { + fn default() -> Self { + Self { num_digits: 0, decimal_point: 0, truncated: false, digits: [0; Self::MAX_DIGITS] } + } +} + +impl Decimal { + /// The maximum number of digits required to unambiguously round a float. + /// + /// For a double-precision IEEE-754 float, this required 767 digits, + /// so we store the max digits + 1. + /// + /// We can exactly represent a float in radix `b` from radix 2 if + /// `b` is divisible by 2. This function calculates the exact number of + /// digits required to exactly represent that float. + /// + /// According to the "Handbook of Floating Point Arithmetic", + /// for IEEE754, with emin being the min exponent, p2 being the + /// precision, and b being the radix, the number of digits follows as: + /// + /// `−emin + p2 + ⌊(emin + 1) log(2, b) − log(1 − 2^(−p2), b)⌋` + /// + /// For f32, this follows as: + /// emin = -126 + /// p2 = 24 + /// + /// For f64, this follows as: + /// emin = -1022 + /// p2 = 53 + /// + /// In Python: + /// `-emin + p2 + math.floor((emin+ 1)*math.log(2, b)-math.log(1-2**(-p2), b))` + pub const MAX_DIGITS: usize = 768; + /// The max digits that can be exactly represented in a 64-bit integer. + pub const MAX_DIGITS_WITHOUT_OVERFLOW: usize = 19; + pub const DECIMAL_POINT_RANGE: i32 = 2047; + + /// Append a digit to the buffer. + pub fn try_add_digit(&mut self, digit: u8) { + if self.num_digits < Self::MAX_DIGITS { + self.digits[self.num_digits] = digit; + } + self.num_digits += 1; + } + + /// Trim trailing zeros from the buffer. + pub fn trim(&mut self) { + // All of the following calls to `Decimal::trim` can't panic because: + // + // 1. `parse_decimal` sets `num_digits` to a max of `Decimal::MAX_DIGITS`. + // 2. `right_shift` sets `num_digits` to `write_index`, which is bounded by `num_digits`. + // 3. `left_shift` `num_digits` to a max of `Decimal::MAX_DIGITS`. + // + // Trim is only called in `right_shift` and `left_shift`. + debug_assert!(self.num_digits <= Self::MAX_DIGITS); + while self.num_digits != 0 && self.digits[self.num_digits - 1] == 0 { + self.num_digits -= 1; + } + } + + pub fn round(&self) -> u64 { + if self.num_digits == 0 || self.decimal_point < 0 { + return 0; + } else if self.decimal_point > 18 { + return 0xFFFF_FFFF_FFFF_FFFF_u64; + } + let dp = self.decimal_point as usize; + let mut n = 0_u64; + for i in 0..dp { + n *= 10; + if i < self.num_digits { + n += self.digits[i] as u64; + } + } + let mut round_up = false; + if dp < self.num_digits { + round_up = self.digits[dp] >= 5; + if self.digits[dp] == 5 && dp + 1 == self.num_digits { + round_up = self.truncated || ((dp != 0) && (1 & self.digits[dp - 1] != 0)) + } + } + if round_up { + n += 1; + } + n + } + + /// Computes decimal * 2^shift. + pub fn left_shift(&mut self, shift: usize) { + if self.num_digits == 0 { + return; + } + let num_new_digits = number_of_digits_decimal_left_shift(self, shift); + let mut read_index = self.num_digits; + let mut write_index = self.num_digits + num_new_digits; + let mut n = 0_u64; + while read_index != 0 { + read_index -= 1; + write_index -= 1; + n += (self.digits[read_index] as u64) << shift; + let quotient = n / 10; + let remainder = n - (10 * quotient); + if write_index < Self::MAX_DIGITS { + self.digits[write_index] = remainder as u8; + } else if remainder > 0 { + self.truncated = true; + } + n = quotient; + } + while n > 0 { + write_index -= 1; + let quotient = n / 10; + let remainder = n - (10 * quotient); + if write_index < Self::MAX_DIGITS { + self.digits[write_index] = remainder as u8; + } else if remainder > 0 { + self.truncated = true; + } + n = quotient; + } + self.num_digits += num_new_digits; + if self.num_digits > Self::MAX_DIGITS { + self.num_digits = Self::MAX_DIGITS; + } + self.decimal_point += num_new_digits as i32; + self.trim(); + } + + /// Computes decimal * 2^-shift. + pub fn right_shift(&mut self, shift: usize) { + let mut read_index = 0; + let mut write_index = 0; + let mut n = 0_u64; + while (n >> shift) == 0 { + if read_index < self.num_digits { + n = (10 * n) + self.digits[read_index] as u64; + read_index += 1; + } else if n == 0 { + return; + } else { + while (n >> shift) == 0 { + n *= 10; + read_index += 1; + } + break; + } + } + self.decimal_point -= read_index as i32 - 1; + if self.decimal_point < -Self::DECIMAL_POINT_RANGE { + // `self = Self::Default()`, but without the overhead of clearing `digits`. + self.num_digits = 0; + self.decimal_point = 0; + self.truncated = false; + return; + } + let mask = (1_u64 << shift) - 1; + while read_index < self.num_digits { + let new_digit = (n >> shift) as u8; + n = (10 * (n & mask)) + self.digits[read_index] as u64; + read_index += 1; + self.digits[write_index] = new_digit; + write_index += 1; + } + while n > 0 { + let new_digit = (n >> shift) as u8; + n = 10 * (n & mask); + if write_index < Self::MAX_DIGITS { + self.digits[write_index] = new_digit; + write_index += 1; + } else if new_digit > 0 { + self.truncated = true; + } + } + self.num_digits = write_index; + self.trim(); + } +} + +/// Parse a big integer representation of the float as a decimal. +pub fn parse_decimal(mut s: &[u8]) -> Decimal { + let mut d = Decimal::default(); + let start = s; + s = s.skip_chars(b'0'); + parse_digits(&mut s, |digit| d.try_add_digit(digit)); + if s.first_is(b'.') { + s = s.advance(1); + let first = s; + // Skip leading zeros. + if d.num_digits == 0 { + s = s.skip_chars(b'0'); + } + while s.len() >= 8 && d.num_digits + 8 < Decimal::MAX_DIGITS { + // SAFETY: s is at least 8 bytes. + let v = unsafe { s.read_u64_unchecked() }; + if !is_8digits(v) { + break; + } + // SAFETY: d.num_digits + 8 is less than d.digits.len() + unsafe { + d.digits[d.num_digits..].write_u64_unchecked(v - 0x3030_3030_3030_3030); + } + d.num_digits += 8; + s = s.advance(8); + } + parse_digits(&mut s, |digit| d.try_add_digit(digit)); + d.decimal_point = s.len() as i32 - first.len() as i32; + } + if d.num_digits != 0 { + // Ignore the trailing zeros if there are any + let mut n_trailing_zeros = 0; + for &c in start[..(start.len() - s.len())].iter().rev() { + if c == b'0' { + n_trailing_zeros += 1; + } else if c != b'.' { + break; + } + } + d.decimal_point += n_trailing_zeros as i32; + d.num_digits -= n_trailing_zeros; + d.decimal_point += d.num_digits as i32; + if d.num_digits > Decimal::MAX_DIGITS { + d.truncated = true; + d.num_digits = Decimal::MAX_DIGITS; + } + } + if s.first_is2(b'e', b'E') { + s = s.advance(1); + let mut neg_exp = false; + if s.first_is(b'-') { + neg_exp = true; + s = s.advance(1); + } else if s.first_is(b'+') { + s = s.advance(1); + } + let mut exp_num = 0_i32; + parse_digits(&mut s, |digit| { + if exp_num < 0x10000 { + exp_num = 10 * exp_num + digit as i32; + } + }); + d.decimal_point += if neg_exp { -exp_num } else { exp_num }; + } + for i in d.num_digits..Decimal::MAX_DIGITS_WITHOUT_OVERFLOW { + d.digits[i] = 0; + } + d +} + +fn number_of_digits_decimal_left_shift(d: &Decimal, mut shift: usize) -> usize { + #[rustfmt::skip] + const TABLE: [u16; 65] = [ + 0x0000, 0x0800, 0x0801, 0x0803, 0x1006, 0x1009, 0x100D, 0x1812, 0x1817, 0x181D, 0x2024, + 0x202B, 0x2033, 0x203C, 0x2846, 0x2850, 0x285B, 0x3067, 0x3073, 0x3080, 0x388E, 0x389C, + 0x38AB, 0x38BB, 0x40CC, 0x40DD, 0x40EF, 0x4902, 0x4915, 0x4929, 0x513E, 0x5153, 0x5169, + 0x5180, 0x5998, 0x59B0, 0x59C9, 0x61E3, 0x61FD, 0x6218, 0x6A34, 0x6A50, 0x6A6D, 0x6A8B, + 0x72AA, 0x72C9, 0x72E9, 0x7B0A, 0x7B2B, 0x7B4D, 0x8370, 0x8393, 0x83B7, 0x83DC, 0x8C02, + 0x8C28, 0x8C4F, 0x9477, 0x949F, 0x94C8, 0x9CF2, 0x051C, 0x051C, 0x051C, 0x051C, + ]; + #[rustfmt::skip] + const TABLE_POW5: [u8; 0x051C] = [ + 5, 2, 5, 1, 2, 5, 6, 2, 5, 3, 1, 2, 5, 1, 5, 6, 2, 5, 7, 8, 1, 2, 5, 3, 9, 0, 6, 2, 5, 1, + 9, 5, 3, 1, 2, 5, 9, 7, 6, 5, 6, 2, 5, 4, 8, 8, 2, 8, 1, 2, 5, 2, 4, 4, 1, 4, 0, 6, 2, 5, + 1, 2, 2, 0, 7, 0, 3, 1, 2, 5, 6, 1, 0, 3, 5, 1, 5, 6, 2, 5, 3, 0, 5, 1, 7, 5, 7, 8, 1, 2, + 5, 1, 5, 2, 5, 8, 7, 8, 9, 0, 6, 2, 5, 7, 6, 2, 9, 3, 9, 4, 5, 3, 1, 2, 5, 3, 8, 1, 4, 6, + 9, 7, 2, 6, 5, 6, 2, 5, 1, 9, 0, 7, 3, 4, 8, 6, 3, 2, 8, 1, 2, 5, 9, 5, 3, 6, 7, 4, 3, 1, + 6, 4, 0, 6, 2, 5, 4, 7, 6, 8, 3, 7, 1, 5, 8, 2, 0, 3, 1, 2, 5, 2, 3, 8, 4, 1, 8, 5, 7, 9, + 1, 0, 1, 5, 6, 2, 5, 1, 1, 9, 2, 0, 9, 2, 8, 9, 5, 5, 0, 7, 8, 1, 2, 5, 5, 9, 6, 0, 4, 6, + 4, 4, 7, 7, 5, 3, 9, 0, 6, 2, 5, 2, 9, 8, 0, 2, 3, 2, 2, 3, 8, 7, 6, 9, 5, 3, 1, 2, 5, 1, + 4, 9, 0, 1, 1, 6, 1, 1, 9, 3, 8, 4, 7, 6, 5, 6, 2, 5, 7, 4, 5, 0, 5, 8, 0, 5, 9, 6, 9, 2, + 3, 8, 2, 8, 1, 2, 5, 3, 7, 2, 5, 2, 9, 0, 2, 9, 8, 4, 6, 1, 9, 1, 4, 0, 6, 2, 5, 1, 8, 6, + 2, 6, 4, 5, 1, 4, 9, 2, 3, 0, 9, 5, 7, 0, 3, 1, 2, 5, 9, 3, 1, 3, 2, 2, 5, 7, 4, 6, 1, 5, + 4, 7, 8, 5, 1, 5, 6, 2, 5, 4, 6, 5, 6, 6, 1, 2, 8, 7, 3, 0, 7, 7, 3, 9, 2, 5, 7, 8, 1, 2, + 5, 2, 3, 2, 8, 3, 0, 6, 4, 3, 6, 5, 3, 8, 6, 9, 6, 2, 8, 9, 0, 6, 2, 5, 1, 1, 6, 4, 1, 5, + 3, 2, 1, 8, 2, 6, 9, 3, 4, 8, 1, 4, 4, 5, 3, 1, 2, 5, 5, 8, 2, 0, 7, 6, 6, 0, 9, 1, 3, 4, + 6, 7, 4, 0, 7, 2, 2, 6, 5, 6, 2, 5, 2, 9, 1, 0, 3, 8, 3, 0, 4, 5, 6, 7, 3, 3, 7, 0, 3, 6, + 1, 3, 2, 8, 1, 2, 5, 1, 4, 5, 5, 1, 9, 1, 5, 2, 2, 8, 3, 6, 6, 8, 5, 1, 8, 0, 6, 6, 4, 0, + 6, 2, 5, 7, 2, 7, 5, 9, 5, 7, 6, 1, 4, 1, 8, 3, 4, 2, 5, 9, 0, 3, 3, 2, 0, 3, 1, 2, 5, 3, + 6, 3, 7, 9, 7, 8, 8, 0, 7, 0, 9, 1, 7, 1, 2, 9, 5, 1, 6, 6, 0, 1, 5, 6, 2, 5, 1, 8, 1, 8, + 9, 8, 9, 4, 0, 3, 5, 4, 5, 8, 5, 6, 4, 7, 5, 8, 3, 0, 0, 7, 8, 1, 2, 5, 9, 0, 9, 4, 9, 4, + 7, 0, 1, 7, 7, 2, 9, 2, 8, 2, 3, 7, 9, 1, 5, 0, 3, 9, 0, 6, 2, 5, 4, 5, 4, 7, 4, 7, 3, 5, + 0, 8, 8, 6, 4, 6, 4, 1, 1, 8, 9, 5, 7, 5, 1, 9, 5, 3, 1, 2, 5, 2, 2, 7, 3, 7, 3, 6, 7, 5, + 4, 4, 3, 2, 3, 2, 0, 5, 9, 4, 7, 8, 7, 5, 9, 7, 6, 5, 6, 2, 5, 1, 1, 3, 6, 8, 6, 8, 3, 7, + 7, 2, 1, 6, 1, 6, 0, 2, 9, 7, 3, 9, 3, 7, 9, 8, 8, 2, 8, 1, 2, 5, 5, 6, 8, 4, 3, 4, 1, 8, + 8, 6, 0, 8, 0, 8, 0, 1, 4, 8, 6, 9, 6, 8, 9, 9, 4, 1, 4, 0, 6, 2, 5, 2, 8, 4, 2, 1, 7, 0, + 9, 4, 3, 0, 4, 0, 4, 0, 0, 7, 4, 3, 4, 8, 4, 4, 9, 7, 0, 7, 0, 3, 1, 2, 5, 1, 4, 2, 1, 0, + 8, 5, 4, 7, 1, 5, 2, 0, 2, 0, 0, 3, 7, 1, 7, 4, 2, 2, 4, 8, 5, 3, 5, 1, 5, 6, 2, 5, 7, 1, + 0, 5, 4, 2, 7, 3, 5, 7, 6, 0, 1, 0, 0, 1, 8, 5, 8, 7, 1, 1, 2, 4, 2, 6, 7, 5, 7, 8, 1, 2, + 5, 3, 5, 5, 2, 7, 1, 3, 6, 7, 8, 8, 0, 0, 5, 0, 0, 9, 2, 9, 3, 5, 5, 6, 2, 1, 3, 3, 7, 8, + 9, 0, 6, 2, 5, 1, 7, 7, 6, 3, 5, 6, 8, 3, 9, 4, 0, 0, 2, 5, 0, 4, 6, 4, 6, 7, 7, 8, 1, 0, + 6, 6, 8, 9, 4, 5, 3, 1, 2, 5, 8, 8, 8, 1, 7, 8, 4, 1, 9, 7, 0, 0, 1, 2, 5, 2, 3, 2, 3, 3, + 8, 9, 0, 5, 3, 3, 4, 4, 7, 2, 6, 5, 6, 2, 5, 4, 4, 4, 0, 8, 9, 2, 0, 9, 8, 5, 0, 0, 6, 2, + 6, 1, 6, 1, 6, 9, 4, 5, 2, 6, 6, 7, 2, 3, 6, 3, 2, 8, 1, 2, 5, 2, 2, 2, 0, 4, 4, 6, 0, 4, + 9, 2, 5, 0, 3, 1, 3, 0, 8, 0, 8, 4, 7, 2, 6, 3, 3, 3, 6, 1, 8, 1, 6, 4, 0, 6, 2, 5, 1, 1, + 1, 0, 2, 2, 3, 0, 2, 4, 6, 2, 5, 1, 5, 6, 5, 4, 0, 4, 2, 3, 6, 3, 1, 6, 6, 8, 0, 9, 0, 8, + 2, 0, 3, 1, 2, 5, 5, 5, 5, 1, 1, 1, 5, 1, 2, 3, 1, 2, 5, 7, 8, 2, 7, 0, 2, 1, 1, 8, 1, 5, + 8, 3, 4, 0, 4, 5, 4, 1, 0, 1, 5, 6, 2, 5, 2, 7, 7, 5, 5, 5, 7, 5, 6, 1, 5, 6, 2, 8, 9, 1, + 3, 5, 1, 0, 5, 9, 0, 7, 9, 1, 7, 0, 2, 2, 7, 0, 5, 0, 7, 8, 1, 2, 5, 1, 3, 8, 7, 7, 7, 8, + 7, 8, 0, 7, 8, 1, 4, 4, 5, 6, 7, 5, 5, 2, 9, 5, 3, 9, 5, 8, 5, 1, 1, 3, 5, 2, 5, 3, 9, 0, + 6, 2, 5, 6, 9, 3, 8, 8, 9, 3, 9, 0, 3, 9, 0, 7, 2, 2, 8, 3, 7, 7, 6, 4, 7, 6, 9, 7, 9, 2, + 5, 5, 6, 7, 6, 2, 6, 9, 5, 3, 1, 2, 5, 3, 4, 6, 9, 4, 4, 6, 9, 5, 1, 9, 5, 3, 6, 1, 4, 1, + 8, 8, 8, 2, 3, 8, 4, 8, 9, 6, 2, 7, 8, 3, 8, 1, 3, 4, 7, 6, 5, 6, 2, 5, 1, 7, 3, 4, 7, 2, + 3, 4, 7, 5, 9, 7, 6, 8, 0, 7, 0, 9, 4, 4, 1, 1, 9, 2, 4, 4, 8, 1, 3, 9, 1, 9, 0, 6, 7, 3, + 8, 2, 8, 1, 2, 5, 8, 6, 7, 3, 6, 1, 7, 3, 7, 9, 8, 8, 4, 0, 3, 5, 4, 7, 2, 0, 5, 9, 6, 2, + 2, 4, 0, 6, 9, 5, 9, 5, 3, 3, 6, 9, 1, 4, 0, 6, 2, 5, + ]; + + shift &= 63; + let x_a = TABLE[shift]; + let x_b = TABLE[shift + 1]; + let num_new_digits = (x_a >> 11) as _; + let pow5_a = (0x7FF & x_a) as usize; + let pow5_b = (0x7FF & x_b) as usize; + let pow5 = &TABLE_POW5[pow5_a..]; + for (i, &p5) in pow5.iter().enumerate().take(pow5_b - pow5_a) { + if i >= d.num_digits { + return num_new_digits - 1; + } else if d.digits[i] == p5 { + continue; + } else if d.digits[i] < p5 { + return num_new_digits - 1; + } else { + return num_new_digits; + } + } + num_new_digits +} diff --git a/library/core/src/num/dec2flt/float.rs b/library/core/src/num/dec2flt/float.rs new file mode 100644 index 00000000000..5921c5ed472 --- /dev/null +++ b/library/core/src/num/dec2flt/float.rs @@ -0,0 +1,207 @@ +//! Helper trait for generic float types. + +use crate::fmt::{Debug, LowerExp}; +use crate::num::FpCategory; +use crate::ops::{Add, Div, Mul, Neg}; + +/// A helper trait to avoid duplicating basically all the conversion code for `f32` and `f64`. +/// +/// See the parent module's doc comment for why this is necessary. +/// +/// Should **never ever** be implemented for other types or be used outside the dec2flt module. +#[doc(hidden)] +pub trait RawFloat: + Sized + + Div<Output = Self> + + Neg<Output = Self> + + Mul<Output = Self> + + Add<Output = Self> + + LowerExp + + PartialEq + + PartialOrd + + Default + + Clone + + Copy + + Debug +{ + const INFINITY: Self; + const NEG_INFINITY: Self; + const NAN: Self; + const NEG_NAN: Self; + + /// The number of bits in the significand, *excluding* the hidden bit. + const MANTISSA_EXPLICIT_BITS: usize; + + // Round-to-even only happens for negative values of q + // when q ≥ −4 in the 64-bit case and when q ≥ −17 in + // the 32-bitcase. + // + // When q ≥ 0,we have that 5^q ≤ 2m+1. In the 64-bit case,we + // have 5^q ≤ 2m+1 ≤ 2^54 or q ≤ 23. In the 32-bit case,we have + // 5^q ≤ 2m+1 ≤ 2^25 or q ≤ 10. + // + // When q < 0, we have w ≥ (2m+1)×5^−q. We must have that w < 2^64 + // so (2m+1)×5^−q < 2^64. We have that 2m+1 > 2^53 (64-bit case) + // or 2m+1 > 2^24 (32-bit case). Hence,we must have 2^53×5^−q < 2^64 + // (64-bit) and 2^24×5^−q < 2^64 (32-bit). Hence we have 5^−q < 2^11 + // or q ≥ −4 (64-bit case) and 5^−q < 2^40 or q ≥ −17 (32-bitcase). + // + // Thus we have that we only need to round ties to even when + // we have that q ∈ [−4,23](in the 64-bit case) or q∈[−17,10] + // (in the 32-bit case). In both cases,the power of five(5^|q|) + // fits in a 64-bit word. + const MIN_EXPONENT_ROUND_TO_EVEN: i32; + const MAX_EXPONENT_ROUND_TO_EVEN: i32; + + // Minimum exponent that for a fast path case, or `-⌊(MANTISSA_EXPLICIT_BITS+1)/log2(5)⌋` + const MIN_EXPONENT_FAST_PATH: i64; + + // Maximum exponent that for a fast path case, or `⌊(MANTISSA_EXPLICIT_BITS+1)/log2(5)⌋` + const MAX_EXPONENT_FAST_PATH: i64; + + // Maximum exponent that can be represented for a disguised-fast path case. + // This is `MAX_EXPONENT_FAST_PATH + ⌊(MANTISSA_EXPLICIT_BITS+1)/log2(10)⌋` + const MAX_EXPONENT_DISGUISED_FAST_PATH: i64; + + // Minimum exponent value `-(1 << (EXP_BITS - 1)) + 1`. + const MINIMUM_EXPONENT: i32; + + // Largest exponent value `(1 << EXP_BITS) - 1`. + const INFINITE_POWER: i32; + + // Index (in bits) of the sign. + const SIGN_INDEX: usize; + + // Smallest decimal exponent for a non-zero value. + const SMALLEST_POWER_OF_TEN: i32; + + // Largest decimal exponent for a non-infinite value. + const LARGEST_POWER_OF_TEN: i32; + + // Maximum mantissa for the fast-path (`1 << 53` for f64). + const MAX_MANTISSA_FAST_PATH: u64 = 2_u64 << Self::MANTISSA_EXPLICIT_BITS; + + /// Convert integer into float through an as cast. + /// This is only called in the fast-path algorithm, and therefore + /// will not lose precision, since the value will always have + /// only if the value is <= Self::MAX_MANTISSA_FAST_PATH. + fn from_u64(v: u64) -> Self; + + /// Performs a raw transmutation from an integer. + fn from_u64_bits(v: u64) -> Self; + + /// Get a small power-of-ten for fast-path multiplication. + fn pow10_fast_path(exponent: usize) -> Self; + + /// Returns the category that this number falls into. + fn classify(self) -> FpCategory; + + /// Returns the mantissa, exponent and sign as integers. + fn integer_decode(self) -> (u64, i16, i8); +} + +impl RawFloat for f32 { + const INFINITY: Self = f32::INFINITY; + const NEG_INFINITY: Self = f32::NEG_INFINITY; + const NAN: Self = f32::NAN; + const NEG_NAN: Self = -f32::NAN; + + const MANTISSA_EXPLICIT_BITS: usize = 23; + const MIN_EXPONENT_ROUND_TO_EVEN: i32 = -17; + const MAX_EXPONENT_ROUND_TO_EVEN: i32 = 10; + const MIN_EXPONENT_FAST_PATH: i64 = -10; // assuming FLT_EVAL_METHOD = 0 + const MAX_EXPONENT_FAST_PATH: i64 = 10; + const MAX_EXPONENT_DISGUISED_FAST_PATH: i64 = 17; + const MINIMUM_EXPONENT: i32 = -127; + const INFINITE_POWER: i32 = 0xFF; + const SIGN_INDEX: usize = 31; + const SMALLEST_POWER_OF_TEN: i32 = -65; + const LARGEST_POWER_OF_TEN: i32 = 38; + + fn from_u64(v: u64) -> Self { + debug_assert!(v <= Self::MAX_MANTISSA_FAST_PATH); + v as _ + } + + fn from_u64_bits(v: u64) -> Self { + f32::from_bits((v & 0xFFFFFFFF) as u32) + } + + fn pow10_fast_path(exponent: usize) -> Self { + #[allow(clippy::use_self)] + const TABLE: [f32; 16] = + [1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 0., 0., 0., 0., 0.]; + TABLE[exponent & 15] + } + + /// Returns the mantissa, exponent and sign as integers. + fn integer_decode(self) -> (u64, i16, i8) { + let bits = self.to_bits(); + let sign: i8 = if bits >> 31 == 0 { 1 } else { -1 }; + let mut exponent: i16 = ((bits >> 23) & 0xff) as i16; + let mantissa = + if exponent == 0 { (bits & 0x7fffff) << 1 } else { (bits & 0x7fffff) | 0x800000 }; + // Exponent bias + mantissa shift + exponent -= 127 + 23; + (mantissa as u64, exponent, sign) + } + + fn classify(self) -> FpCategory { + self.classify() + } +} + +impl RawFloat for f64 { + const INFINITY: Self = f64::INFINITY; + const NEG_INFINITY: Self = f64::NEG_INFINITY; + const NAN: Self = f64::NAN; + const NEG_NAN: Self = -f64::NAN; + + const MANTISSA_EXPLICIT_BITS: usize = 52; + const MIN_EXPONENT_ROUND_TO_EVEN: i32 = -4; + const MAX_EXPONENT_ROUND_TO_EVEN: i32 = 23; + const MIN_EXPONENT_FAST_PATH: i64 = -22; // assuming FLT_EVAL_METHOD = 0 + const MAX_EXPONENT_FAST_PATH: i64 = 22; + const MAX_EXPONENT_DISGUISED_FAST_PATH: i64 = 37; + const MINIMUM_EXPONENT: i32 = -1023; + const INFINITE_POWER: i32 = 0x7FF; + const SIGN_INDEX: usize = 63; + const SMALLEST_POWER_OF_TEN: i32 = -342; + const LARGEST_POWER_OF_TEN: i32 = 308; + + fn from_u64(v: u64) -> Self { + debug_assert!(v <= Self::MAX_MANTISSA_FAST_PATH); + v as _ + } + + fn from_u64_bits(v: u64) -> Self { + f64::from_bits(v) + } + + fn pow10_fast_path(exponent: usize) -> Self { + const TABLE: [f64; 32] = [ + 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, + 1e16, 1e17, 1e18, 1e19, 1e20, 1e21, 1e22, 0., 0., 0., 0., 0., 0., 0., 0., 0., + ]; + TABLE[exponent & 31] + } + + /// Returns the mantissa, exponent and sign as integers. + fn integer_decode(self) -> (u64, i16, i8) { + let bits = self.to_bits(); + let sign: i8 = if bits >> 63 == 0 { 1 } else { -1 }; + let mut exponent: i16 = ((bits >> 52) & 0x7ff) as i16; + let mantissa = if exponent == 0 { + (bits & 0xfffffffffffff) << 1 + } else { + (bits & 0xfffffffffffff) | 0x10000000000000 + }; + // Exponent bias + mantissa shift + exponent -= 1023 + 52; + (mantissa, exponent, sign) + } + + fn classify(self) -> FpCategory { + self.classify() + } +} diff --git a/library/core/src/num/dec2flt/fpu.rs b/library/core/src/num/dec2flt/fpu.rs new file mode 100644 index 00000000000..24492d9a1dd --- /dev/null +++ b/library/core/src/num/dec2flt/fpu.rs @@ -0,0 +1,89 @@ +//! Platform-specific, assembly instructions to avoid +//! intermediate rounding on architectures with FPUs. + +pub use fpu_precision::set_precision; + +// On x86, the x87 FPU is used for float operations if the SSE/SSE2 extensions are not available. +// The x87 FPU operates with 80 bits of precision by default, which means that operations will +// round to 80 bits causing double rounding to happen when values are eventually represented as +// 32/64 bit float values. To overcome this, the FPU control word can be set so that the +// computations are performed in the desired precision. +#[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] +mod fpu_precision { + use core::mem::size_of; + + /// A structure used to preserve the original value of the FPU control word, so that it can be + /// restored when the structure is dropped. + /// + /// The x87 FPU is a 16-bits register whose fields are as follows: + /// + /// | 12-15 | 10-11 | 8-9 | 6-7 | 5 | 4 | 3 | 2 | 1 | 0 | + /// |------:|------:|----:|----:|---:|---:|---:|---:|---:|---:| + /// | | RC | PC | | PM | UM | OM | ZM | DM | IM | + /// + /// The documentation for all of the fields is available in the IA-32 Architectures Software + /// Developer's Manual (Volume 1). + /// + /// The only field which is relevant for the following code is PC, Precision Control. This + /// field determines the precision of the operations performed by the FPU. It can be set to: + /// - 0b00, single precision i.e., 32-bits + /// - 0b10, double precision i.e., 64-bits + /// - 0b11, double extended precision i.e., 80-bits (default state) + /// The 0b01 value is reserved and should not be used. + pub struct FPUControlWord(u16); + + fn set_cw(cw: u16) { + // SAFETY: the `fldcw` instruction has been audited to be able to work correctly with + // any `u16` + unsafe { + asm!( + "fldcw word ptr [{}]", + in(reg) &cw, + options(nostack), + ) + } + } + + /// Sets the precision field of the FPU to `T` and returns a `FPUControlWord`. + pub fn set_precision<T>() -> FPUControlWord { + let mut cw = 0_u16; + + // Compute the value for the Precision Control field that is appropriate for `T`. + let cw_precision = match size_of::<T>() { + 4 => 0x0000, // 32 bits + 8 => 0x0200, // 64 bits + _ => 0x0300, // default, 80 bits + }; + + // Get the original value of the control word to restore it later, when the + // `FPUControlWord` structure is dropped + // SAFETY: the `fnstcw` instruction has been audited to be able to work correctly with + // any `u16` + unsafe { + asm!( + "fnstcw word ptr [{}]", + in(reg) &mut cw, + options(nostack), + ) + } + + // Set the control word to the desired precision. This is achieved by masking away the old + // precision (bits 8 and 9, 0x300) and replacing it with the precision flag computed above. + set_cw((cw & 0xFCFF) | cw_precision); + + FPUControlWord(cw) + } + + impl Drop for FPUControlWord { + fn drop(&mut self) { + set_cw(self.0) + } + } +} + +// In most architectures, floating point operations have an explicit bit size, therefore the +// precision of the computation is determined on a per-operation basis. +#[cfg(any(not(target_arch = "x86"), target_feature = "sse2"))] +mod fpu_precision { + pub fn set_precision<T>() {} +} diff --git a/library/core/src/num/dec2flt/lemire.rs b/library/core/src/num/dec2flt/lemire.rs new file mode 100644 index 00000000000..9b7efc3d556 --- /dev/null +++ b/library/core/src/num/dec2flt/lemire.rs @@ -0,0 +1,166 @@ +//! Implementation of the Eisel-Lemire algorithm. + +use crate::num::dec2flt::common::BiasedFp; +use crate::num::dec2flt::float::RawFloat; +use crate::num::dec2flt::table::{ + LARGEST_POWER_OF_FIVE, POWER_OF_FIVE_128, SMALLEST_POWER_OF_FIVE, +}; + +/// Compute a float using an extended-precision representation. +/// +/// Fast conversion of a the significant digits and decimal exponent +/// a float to a extended representation with a binary float. This +/// algorithm will accurately parse the vast majority of cases, +/// and uses a 128-bit representation (with a fallback 192-bit +/// representation). +/// +/// This algorithm scales the exponent by the decimal exponent +/// using pre-computed powers-of-5, and calculates if the +/// representation can be unambiguously rounded to the nearest +/// machine float. Near-halfway cases are not handled here, +/// and are represented by a negative, biased binary exponent. +/// +/// The algorithm is described in detail in "Daniel Lemire, Number Parsing +/// at a Gigabyte per Second" in section 5, "Fast Algorithm", and +/// section 6, "Exact Numbers And Ties", available online: +/// <https://arxiv.org/abs/2101.11408.pdf>. +pub fn compute_float<F: RawFloat>(q: i64, mut w: u64) -> BiasedFp { + let fp_zero = BiasedFp::zero_pow2(0); + let fp_inf = BiasedFp::zero_pow2(F::INFINITE_POWER); + let fp_error = BiasedFp::zero_pow2(-1); + + // Short-circuit if the value can only be a literal 0 or infinity. + if w == 0 || q < F::SMALLEST_POWER_OF_TEN as i64 { + return fp_zero; + } else if q > F::LARGEST_POWER_OF_TEN as i64 { + return fp_inf; + } + // Normalize our significant digits, so the most-significant bit is set. + let lz = w.leading_zeros(); + w <<= lz; + let (lo, hi) = compute_product_approx(q, w, F::MANTISSA_EXPLICIT_BITS + 3); + if lo == 0xFFFF_FFFF_FFFF_FFFF { + // If we have failed to approximate w x 5^-q with our 128-bit value. + // Since the addition of 1 could lead to an overflow which could then + // round up over the half-way point, this can lead to improper rounding + // of a float. + // + // However, this can only occur if q ∈ [-27, 55]. The upper bound of q + // is 55 because 5^55 < 2^128, however, this can only happen if 5^q > 2^64, + // since otherwise the product can be represented in 64-bits, producing + // an exact result. For negative exponents, rounding-to-even can + // only occur if 5^-q < 2^64. + // + // For detailed explanations of rounding for negative exponents, see + // <https://arxiv.org/pdf/2101.11408.pdf#section.9.1>. For detailed + // explanations of rounding for positive exponents, see + // <https://arxiv.org/pdf/2101.11408.pdf#section.8>. + let inside_safe_exponent = (q >= -27) && (q <= 55); + if !inside_safe_exponent { + return fp_error; + } + } + let upperbit = (hi >> 63) as i32; + let mut mantissa = hi >> (upperbit + 64 - F::MANTISSA_EXPLICIT_BITS as i32 - 3); + let mut power2 = power(q as i32) + upperbit - lz as i32 - F::MINIMUM_EXPONENT; + if power2 <= 0 { + if -power2 + 1 >= 64 { + // Have more than 64 bits below the minimum exponent, must be 0. + return fp_zero; + } + // Have a subnormal value. + mantissa >>= -power2 + 1; + mantissa += mantissa & 1; + mantissa >>= 1; + power2 = (mantissa >= (1_u64 << F::MANTISSA_EXPLICIT_BITS)) as i32; + return BiasedFp { f: mantissa, e: power2 }; + } + // Need to handle rounding ties. Normally, we need to round up, + // but if we fall right in between and and we have an even basis, we + // need to round down. + // + // This will only occur if: + // 1. The lower 64 bits of the 128-bit representation is 0. + // IE, 5^q fits in single 64-bit word. + // 2. The least-significant bit prior to truncated mantissa is odd. + // 3. All the bits truncated when shifting to mantissa bits + 1 are 0. + // + // Or, we may fall between two floats: we are exactly halfway. + if lo <= 1 + && q >= F::MIN_EXPONENT_ROUND_TO_EVEN as i64 + && q <= F::MAX_EXPONENT_ROUND_TO_EVEN as i64 + && mantissa & 3 == 1 + && (mantissa << (upperbit + 64 - F::MANTISSA_EXPLICIT_BITS as i32 - 3)) == hi + { + // Zero the lowest bit, so we don't round up. + mantissa &= !1_u64; + } + // Round-to-even, then shift the significant digits into place. + mantissa += mantissa & 1; + mantissa >>= 1; + if mantissa >= (2_u64 << F::MANTISSA_EXPLICIT_BITS) { + // Rounding up overflowed, so the carry bit is set. Set the + // mantissa to 1 (only the implicit, hidden bit is set) and + // increase the exponent. + mantissa = 1_u64 << F::MANTISSA_EXPLICIT_BITS; + power2 += 1; + } + // Zero out the hidden bit. + mantissa &= !(1_u64 << F::MANTISSA_EXPLICIT_BITS); + if power2 >= F::INFINITE_POWER { + // Exponent is above largest normal value, must be infinite. + return fp_inf; + } + BiasedFp { f: mantissa, e: power2 } +} + +/// Calculate a base 2 exponent from a decimal exponent. +/// This uses a pre-computed integer approximation for +/// log2(10), where 217706 / 2^16 is accurate for the +/// entire range of non-finite decimal exponents. +fn power(q: i32) -> i32 { + (q.wrapping_mul(152_170 + 65536) >> 16) + 63 +} + +fn full_multiplication(a: u64, b: u64) -> (u64, u64) { + let r = (a as u128) * (b as u128); + (r as u64, (r >> 64) as u64) +} + +// This will compute or rather approximate w * 5**q and return a pair of 64-bit words +// approximating the result, with the "high" part corresponding to the most significant +// bits and the low part corresponding to the least significant bits. +fn compute_product_approx(q: i64, w: u64, precision: usize) -> (u64, u64) { + debug_assert!(q >= SMALLEST_POWER_OF_FIVE as i64); + debug_assert!(q <= LARGEST_POWER_OF_FIVE as i64); + debug_assert!(precision <= 64); + + let mask = if precision < 64 { + 0xFFFF_FFFF_FFFF_FFFF_u64 >> precision + } else { + 0xFFFF_FFFF_FFFF_FFFF_u64 + }; + + // 5^q < 2^64, then the multiplication always provides an exact value. + // That means whenever we need to round ties to even, we always have + // an exact value. + let index = (q - SMALLEST_POWER_OF_FIVE as i64) as usize; + let (lo5, hi5) = POWER_OF_FIVE_128[index]; + // Only need one multiplication as long as there is 1 zero but + // in the explicit mantissa bits, +1 for the hidden bit, +1 to + // determine the rounding direction, +1 for if the computed + // product has a leading zero. + let (mut first_lo, mut first_hi) = full_multiplication(w, lo5); + if first_hi & mask == mask { + // Need to do a second multiplication to get better precision + // for the lower product. This will always be exact + // where q is < 55, since 5^55 < 2^128. If this wraps, + // then we need to need to round up the hi product. + let (_, second_hi) = full_multiplication(w, hi5); + first_lo = first_lo.wrapping_add(second_hi); + if second_hi > first_lo { + first_hi += 1; + } + } + (first_lo, first_hi) +} diff --git a/library/core/src/num/dec2flt/mod.rs b/library/core/src/num/dec2flt/mod.rs index f008a64ffe6..c78492f5ae2 100644 --- a/library/core/src/num/dec2flt/mod.rs +++ b/library/core/src/num/dec2flt/mod.rs @@ -27,20 +27,12 @@ //! //! We then try a long chain of progressively more general and expensive special cases using //! machine-sized integers and small, fixed-sized floating point numbers (first `f32`/`f64`, then -//! a type with 64 bit significand, `Fp`). When all these fail, we bite the bullet and resort to a -//! simple but very slow algorithm that involved computing `f * 10^e` fully and doing an iterative -//! search for the best approximation. -//! -//! Primarily, this module and its children implement the algorithms described in: -//! "How to Read Floating Point Numbers Accurately" by William D. Clinger, -//! available online: <http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.45.4152> -//! -//! In addition, there are numerous helper functions that are used in the paper but not available -//! in Rust (or at least in core). Our version is additionally complicated by the need to handle -//! overflow and underflow and the desire to handle subnormal numbers. Bellerophon and -//! Algorithm R have trouble with overflow, subnormals, and underflow. We conservatively switch to -//! Algorithm M (with the modifications described in section 8 of the paper) well before the -//! inputs get into the critical region. +//! a type with 64 bit significand). The extended-precision algorithm +//! uses the Eisel-Lemire algorithm, which uses a 128-bit (or 192-bit) +//! representation that can accurately and quickly compute the vast majority +//! of floats. When all these fail, we bite the bullet and resort to using +//! a large-decimal representation, shifting the digits into range, calculating +//! the upper significant bits and exactly round to the nearest representation. //! //! Another aspect that needs attention is the ``RawFloat`` trait by which almost all functions //! are parametrized. One might think that it's enough to parse to `f64` and cast the result to @@ -54,10 +46,9 @@ //! operations as well, if you want 0.5 ULP accuracy you need to do *everything* in full precision //! and round *exactly once, at the end*, by considering all truncated bits at once. //! -//! FIXME: Although some code duplication is necessary, perhaps parts of the code could be shuffled -//! around such that less code is duplicated. Large parts of the algorithms are independent of the -//! float type to output, or only needs access to a few constants, which could be passed in as -//! parameters. +//! Primarily, this module and its children implement the algorithms described in: +//! "Number Parsing at a Gigabyte per Second", available online: +//! <https://arxiv.org/abs/2101.11408>. //! //! # Other //! @@ -87,16 +78,22 @@ use crate::fmt; use crate::str::FromStr; -use self::num::digits_to_big; -use self::parse::{parse_decimal, Decimal, ParseResult, Sign}; -use self::rawfp::RawFloat; +use self::common::{BiasedFp, ByteSlice}; +use self::float::RawFloat; +use self::lemire::compute_float; +use self::parse::{parse_inf_nan, parse_number}; +use self::slow::parse_long_mantissa; -mod algorithm; -mod num; +mod common; +mod decimal; +mod fpu; +mod slow; mod table; -// These two have their own tests. +// float is used in flt2dec, and all are used in unit tests. +pub mod float; +pub mod lemire; +pub mod number; pub mod parse; -pub mod rawfp; macro_rules! from_str_float_impl { ($t:ty) => { @@ -136,13 +133,6 @@ macro_rules! from_str_float_impl { /// /// [EBNF]: https://www.w3.org/TR/REC-xml/#sec-notation /// - /// # Known bugs - /// - /// In some situations, some strings that should create a valid float - /// instead return an error. See [issue #31407] for details. - /// - /// [issue #31407]: https://github.com/rust-lang/rust/issues/31407 - /// /// # Arguments /// /// * src - A string @@ -211,148 +201,70 @@ impl fmt::Display for ParseFloatError { } } -fn pfe_empty() -> ParseFloatError { +pub(super) fn pfe_empty() -> ParseFloatError { ParseFloatError { kind: FloatErrorKind::Empty } } -fn pfe_invalid() -> ParseFloatError { +// Used in unit tests, keep public. +// This is much better than making FloatErrorKind and ParseFloatError::kind public. +pub fn pfe_invalid() -> ParseFloatError { ParseFloatError { kind: FloatErrorKind::Invalid } } -/// Splits a decimal string into sign and the rest, without inspecting or validating the rest. -fn extract_sign(s: &str) -> (Sign, &str) { - match s.as_bytes()[0] { - b'+' => (Sign::Positive, &s[1..]), - b'-' => (Sign::Negative, &s[1..]), - // If the string is invalid, we never use the sign, so we don't need to validate here. - _ => (Sign::Positive, s), - } +/// Converts a `BiasedFp` to the closest machine float type. +fn biased_fp_to_float<T: RawFloat>(x: BiasedFp) -> T { + let mut word = x.f; + word |= (x.e as u64) << T::MANTISSA_EXPLICIT_BITS; + T::from_u64_bits(word) } /// Converts a decimal string into a floating point number. -fn dec2flt<T: RawFloat>(s: &str) -> Result<T, ParseFloatError> { - if s.is_empty() { +pub fn dec2flt<F: RawFloat>(s: &str) -> Result<F, ParseFloatError> { + let mut s = s.as_bytes(); + let c = if let Some(&c) = s.first() { + c + } else { return Err(pfe_empty()); + }; + let negative = c == b'-'; + if c == b'-' || c == b'+' { + s = s.advance(1); + } + if s.is_empty() { + return Err(pfe_invalid()); } - let (sign, s) = extract_sign(s); - let flt = match parse_decimal(s) { - ParseResult::Valid(decimal) => convert(decimal)?, - ParseResult::ShortcutToInf => T::INFINITY, - ParseResult::ShortcutToZero => T::ZERO, - ParseResult::Invalid => { - if s.eq_ignore_ascii_case("nan") { - T::NAN - } else if s.eq_ignore_ascii_case("inf") || s.eq_ignore_ascii_case("infinity") { - T::INFINITY + + let num = match parse_number(s, negative) { + Some(r) => r, + None => { + if let Some(value) = parse_inf_nan(s, negative) { + return Ok(value); } else { return Err(pfe_invalid()); } } }; - - match sign { - Sign::Positive => Ok(flt), - Sign::Negative => Ok(-flt), + if let Some(value) = num.try_fast_path::<F>() { + return Ok(value); } -} - -/// The main workhorse for the decimal-to-float conversion: Orchestrate all the preprocessing -/// and figure out which algorithm should do the actual conversion. -fn convert<T: RawFloat>(mut decimal: Decimal<'_>) -> Result<T, ParseFloatError> { - simplify(&mut decimal); - if let Some(x) = trivial_cases(&decimal) { - return Ok(x); - } - // Remove/shift out the decimal point. - let e = decimal.exp - decimal.fractional.len() as i64; - if let Some(x) = algorithm::fast_path(decimal.integral, decimal.fractional, e) { - return Ok(x); - } - // Big32x40 is limited to 1280 bits, which translates to about 385 decimal digits. - // If we exceed this, we'll crash, so we error out before getting too close (within 10^10). - let upper_bound = bound_intermediate_digits(&decimal, e); - if upper_bound > 375 { - return Err(pfe_invalid()); - } - let f = digits_to_big(decimal.integral, decimal.fractional); - - // Now the exponent certainly fits in 16 bit, which is used throughout the main algorithms. - let e = e as i16; - // FIXME These bounds are rather conservative. A more careful analysis of the failure modes - // of Bellerophon could allow using it in more cases for a massive speed up. - let exponent_in_range = table::MIN_E <= e && e <= table::MAX_E; - let value_in_range = upper_bound <= T::MAX_NORMAL_DIGITS as u64; - if exponent_in_range && value_in_range { - Ok(algorithm::bellerophon(&f, e)) - } else { - Ok(algorithm::algorithm_m(&f, e)) - } -} -// As written, this optimizes badly (see #27130, though it refers to an old version of the code). -// `inline(always)` is a workaround for that. There are only two call sites overall and it doesn't -// make code size worse. - -/// Strip zeros where possible, even when this requires changing the exponent -#[inline(always)] -fn simplify(decimal: &mut Decimal<'_>) { - let is_zero = &|&&d: &&u8| -> bool { d == b'0' }; - // Trimming these zeros does not change anything but may enable the fast path (< 15 digits). - let leading_zeros = decimal.integral.iter().take_while(is_zero).count(); - decimal.integral = &decimal.integral[leading_zeros..]; - let trailing_zeros = decimal.fractional.iter().rev().take_while(is_zero).count(); - let end = decimal.fractional.len() - trailing_zeros; - decimal.fractional = &decimal.fractional[..end]; - // Simplify numbers of the form 0.0...x and x...0.0, adjusting the exponent accordingly. - // This may not always be a win (possibly pushes some numbers out of the fast path), but it - // simplifies other parts significantly (notably, approximating the magnitude of the value). - if decimal.integral.is_empty() { - let leading_zeros = decimal.fractional.iter().take_while(is_zero).count(); - decimal.fractional = &decimal.fractional[leading_zeros..]; - decimal.exp -= leading_zeros as i64; - } else if decimal.fractional.is_empty() { - let trailing_zeros = decimal.integral.iter().rev().take_while(is_zero).count(); - let end = decimal.integral.len() - trailing_zeros; - decimal.integral = &decimal.integral[..end]; - decimal.exp += trailing_zeros as i64; + // If significant digits were truncated, then we can have rounding error + // only if `mantissa + 1` produces a different result. We also avoid + // redundantly using the Eisel-Lemire algorithm if it was unable to + // correctly round on the first pass. + let mut fp = compute_float::<F>(num.exponent, num.mantissa); + if num.many_digits && fp.e >= 0 && fp != compute_float::<F>(num.exponent, num.mantissa + 1) { + fp.e = -1; } -} - -/// Returns a quick-an-dirty upper bound on the size (log10) of the largest value that Algorithm R -/// and Algorithm M will compute while working on the given decimal. -fn bound_intermediate_digits(decimal: &Decimal<'_>, e: i64) -> u64 { - // We don't need to worry too much about overflow here thanks to trivial_cases() and the - // parser, which filter out the most extreme inputs for us. - let f_len: u64 = decimal.integral.len() as u64 + decimal.fractional.len() as u64; - if e >= 0 { - // In the case e >= 0, both algorithms compute about `f * 10^e`. Algorithm R proceeds to - // do some complicated calculations with this but we can ignore that for the upper bound - // because it also reduces the fraction beforehand, so we have plenty of buffer there. - f_len + (e as u64) - } else { - // If e < 0, Algorithm R does roughly the same thing, but Algorithm M differs: - // It tries to find a positive number k such that `f << k / 10^e` is an in-range - // significand. This will result in about `2^53 * f * 10^e` < `10^17 * f * 10^e`. - // One input that triggers this is 0.33...33 (375 x 3). - f_len + e.unsigned_abs() + 17 + // Unable to correctly round the float using the Eisel-Lemire algorithm. + // Fallback to a slower, but always correct algorithm. + if fp.e < 0 { + fp = parse_long_mantissa::<F>(s); } -} -/// Detects obvious overflows and underflows without even looking at the decimal digits. -fn trivial_cases<T: RawFloat>(decimal: &Decimal<'_>) -> Option<T> { - // There were zeros but they were stripped by simplify() - if decimal.integral.is_empty() && decimal.fractional.is_empty() { - return Some(T::ZERO); - } - // This is a crude approximation of ceil(log10(the real value)). We don't need to worry too - // much about overflow here because the input length is tiny (at least compared to 2^64) and - // the parser already handles exponents whose absolute value is greater than 10^18 - // (which is still 10^19 short of 2^64). - let max_place = decimal.exp + decimal.integral.len() as i64; - if max_place > T::INF_CUTOFF { - return Some(T::INFINITY); - } else if max_place < T::ZERO_CUTOFF { - return Some(T::ZERO); + let mut float = biased_fp_to_float::<F>(fp); + if num.negative { + float = -float; } - None + Ok(float) } diff --git a/library/core/src/num/dec2flt/num.rs b/library/core/src/num/dec2flt/num.rs deleted file mode 100644 index 208783dd32f..00000000000 --- a/library/core/src/num/dec2flt/num.rs +++ /dev/null @@ -1,81 +0,0 @@ -//! Utility functions for bignums that don't make too much sense to turn into methods. - -// FIXME This module's name is a bit unfortunate, since other modules also import `core::num`. - -use crate::cmp::Ordering::{self, Equal, Greater, Less}; - -pub use crate::num::bignum::Big32x40 as Big; - -/// Test whether truncating all bits less significant than `ones_place` introduces -/// a relative error less, equal, or greater than 0.5 ULP. -pub fn compare_with_half_ulp(f: &Big, ones_place: usize) -> Ordering { - if ones_place == 0 { - return Less; - } - let half_bit = ones_place - 1; - if f.get_bit(half_bit) == 0 { - // < 0.5 ULP - return Less; - } - // If all remaining bits are zero, it's = 0.5 ULP, otherwise > 0.5 - // If there are no more bits (half_bit == 0), the below also correctly returns Equal. - for i in 0..half_bit { - if f.get_bit(i) == 1 { - return Greater; - } - } - Equal -} - -/// Converts an ASCII string containing only decimal digits to a `u64`. -/// -/// Does not perform checks for overflow or invalid characters, so if the caller is not careful, -/// the result is bogus and can panic (though it won't be `unsafe`). Additionally, empty strings -/// are treated as zero. This function exists because -/// -/// 1. using `FromStr` on `&[u8]` requires `from_utf8_unchecked`, which is bad, and -/// 2. piecing together the results of `integral.parse()` and `fractional.parse()` is -/// more complicated than this entire function. -pub fn from_str_unchecked<'a, T>(bytes: T) -> u64 -where - T: IntoIterator<Item = &'a u8>, -{ - let mut result = 0; - for &c in bytes { - result = result * 10 + (c - b'0') as u64; - } - result -} - -/// Converts a string of ASCII digits into a bignum. -/// -/// Like `from_str_unchecked`, this function relies on the parser to weed out non-digits. -pub fn digits_to_big(integral: &[u8], fractional: &[u8]) -> Big { - let mut f = Big::from_small(0); - for &c in integral.iter().chain(fractional) { - let n = (c - b'0') as u32; - f.mul_small(10); - f.add_small(n); - } - f -} - -/// Unwraps a bignum into a 64 bit integer. Panics if the number is too large. -pub fn to_u64(x: &Big) -> u64 { - assert!(x.bit_length() < 64); - let d = x.digits(); - if d.len() < 2 { d[0] as u64 } else { (d[1] as u64) << 32 | d[0] as u64 } -} - -/// Extracts a range of bits. - -/// Index 0 is the least significant bit and the range is half-open as usual. -/// Panics if asked to extract more bits than fit into the return type. -pub fn get_bits(x: &Big, start: usize, end: usize) -> u64 { - assert!(end - start <= 64); - let mut result: u64 = 0; - for i in (start..end).rev() { - result = result << 1 | x.get_bit(i) as u64; - } - result -} diff --git a/library/core/src/num/dec2flt/number.rs b/library/core/src/num/dec2flt/number.rs new file mode 100644 index 00000000000..36432718af4 --- /dev/null +++ b/library/core/src/num/dec2flt/number.rs @@ -0,0 +1,86 @@ +//! Representation of a float as the significant digits and exponent. + +use crate::num::dec2flt::float::RawFloat; +use crate::num::dec2flt::fpu::set_precision; + +#[rustfmt::skip] +const INT_POW10: [u64; 16] = [ + 1, + 10, + 100, + 1000, + 10000, + 100000, + 1000000, + 10000000, + 100000000, + 1000000000, + 10000000000, + 100000000000, + 1000000000000, + 10000000000000, + 100000000000000, + 1000000000000000, +]; + +#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)] +pub struct Number { + pub exponent: i64, + pub mantissa: u64, + pub negative: bool, + pub many_digits: bool, +} + +impl Number { + /// Detect if the float can be accurately reconstructed from native floats. + fn is_fast_path<F: RawFloat>(&self) -> bool { + F::MIN_EXPONENT_FAST_PATH <= self.exponent + && self.exponent <= F::MAX_EXPONENT_DISGUISED_FAST_PATH + && self.mantissa <= F::MAX_MANTISSA_FAST_PATH + && !self.many_digits + } + + /// The fast path algorithmn using machine-sized integers and floats. + /// + /// This is extracted into a separate function so that it can be attempted before constructing + /// a Decimal. This only works if both the mantissa and the exponent + /// can be exactly represented as a machine float, since IEE-754 guarantees + /// no rounding will occur. + /// + /// There is an exception: disguised fast-path cases, where we can shift + /// powers-of-10 from the exponent to the significant digits. + pub fn try_fast_path<F: RawFloat>(&self) -> Option<F> { + // The fast path crucially depends on arithmetic being rounded to the correct number of bits + // without any intermediate rounding. On x86 (without SSE or SSE2) this requires the precision + // of the x87 FPU stack to be changed so that it directly rounds to 64/32 bit. + // The `set_precision` function takes care of setting the precision on architectures which + // require setting it by changing the global state (like the control word of the x87 FPU). + let _cw = set_precision::<F>(); + + if self.is_fast_path::<F>() { + let mut value = if self.exponent <= F::MAX_EXPONENT_FAST_PATH { + // normal fast path + let value = F::from_u64(self.mantissa); + if self.exponent < 0 { + value / F::pow10_fast_path((-self.exponent) as _) + } else { + value * F::pow10_fast_path(self.exponent as _) + } + } else { + // disguised fast path + let shift = self.exponent - F::MAX_EXPONENT_FAST_PATH; + let mantissa = self.mantissa.checked_mul(INT_POW10[shift as usize])?; + if mantissa > F::MAX_MANTISSA_FAST_PATH { + return None; + } + F::from_u64(mantissa) * F::pow10_fast_path(F::MAX_EXPONENT_FAST_PATH as _) + }; + if self.negative { + value = -value; + } + Some(value) + } else { + None + } + } +} diff --git a/library/core/src/num/dec2flt/parse.rs b/library/core/src/num/dec2flt/parse.rs index 858cc3c9b01..fa677bf5123 100644 --- a/library/core/src/num/dec2flt/parse.rs +++ b/library/core/src/num/dec2flt/parse.rs @@ -1,121 +1,233 @@ -//! Validating and decomposing a decimal string of the form: -//! -//! `(digits | digits? '.'? digits?) (('e' | 'E') ('+' | '-')? digits)?` -//! -//! In other words, standard floating-point syntax, with two exceptions: No sign, and no -//! handling of "inf" and "NaN". These are handled by the driver function (super::dec2flt). -//! -//! Although recognizing valid inputs is relatively easy, this module also has to reject the -//! countless invalid variations, never panic, and perform numerous checks that the other -//! modules rely on to not panic (or overflow) in turn. -//! To make matters worse, all that happens in a single pass over the input. -//! So, be careful when modifying anything, and double-check with the other modules. -use self::ParseResult::{Invalid, ShortcutToInf, ShortcutToZero, Valid}; -use super::num; - -#[derive(Debug)] -pub enum Sign { - Positive, - Negative, +//! Functions to parse floating-point numbers. + +use crate::num::dec2flt::common::{is_8digits, AsciiStr, ByteSlice}; +use crate::num::dec2flt::float::RawFloat; +use crate::num::dec2flt::number::Number; + +const MIN_19DIGIT_INT: u64 = 100_0000_0000_0000_0000; + +/// Parse 8 digits, loaded as bytes in little-endian order. +/// +/// This uses the trick where every digit is in [0x030, 0x39], +/// and therefore can be parsed in 3 multiplications, much +/// faster than the normal 8. +/// +/// This is based off the algorithm described in "Fast numeric string to +/// int", available here: <https://johnnylee-sde.github.io/Fast-numeric-string-to-int/>. +fn parse_8digits(mut v: u64) -> u64 { + const MASK: u64 = 0x0000_00FF_0000_00FF; + const MUL1: u64 = 0x000F_4240_0000_0064; + const MUL2: u64 = 0x0000_2710_0000_0001; + v -= 0x3030_3030_3030_3030; + v = (v * 10) + (v >> 8); // will not overflow, fits in 63 bits + let v1 = (v & MASK).wrapping_mul(MUL1); + let v2 = ((v >> 16) & MASK).wrapping_mul(MUL2); + ((v1.wrapping_add(v2) >> 32) as u32) as u64 } -#[derive(Debug, PartialEq, Eq)] -/// The interesting parts of a decimal string. -pub struct Decimal<'a> { - pub integral: &'a [u8], - pub fractional: &'a [u8], - /// The decimal exponent, guaranteed to have fewer than 18 decimal digits. - pub exp: i64, +/// Parse digits until a non-digit character is found. +fn try_parse_digits(s: &mut AsciiStr<'_>, x: &mut u64) { + // may cause overflows, to be handled later + s.parse_digits(|digit| { + *x = x.wrapping_mul(10).wrapping_add(digit as _); + }); } -impl<'a> Decimal<'a> { - pub fn new(integral: &'a [u8], fractional: &'a [u8], exp: i64) -> Decimal<'a> { - Decimal { integral, fractional, exp } +/// Parse up to 19 digits (the max that can be stored in a 64-bit integer). +fn try_parse_19digits(s: &mut AsciiStr<'_>, x: &mut u64) { + while *x < MIN_19DIGIT_INT { + if let Some(&c) = s.as_ref().first() { + let digit = c.wrapping_sub(b'0'); + if digit < 10 { + *x = (*x * 10) + digit as u64; // no overflows here + // SAFETY: cannot be empty + unsafe { + s.step(); + } + } else { + break; + } + } else { + break; + } } } -#[derive(Debug, PartialEq, Eq)] -pub enum ParseResult<'a> { - Valid(Decimal<'a>), - ShortcutToInf, - ShortcutToZero, - Invalid, +/// Try to parse 8 digits at a time, using an optimized algorithm. +fn try_parse_8digits(s: &mut AsciiStr<'_>, x: &mut u64) { + // may cause overflows, to be handled later + if let Some(v) = s.read_u64() { + if is_8digits(v) { + *x = x.wrapping_mul(1_0000_0000).wrapping_add(parse_8digits(v)); + // SAFETY: already ensured the buffer was >= 8 bytes in read_u64. + unsafe { + s.step_by(8); + } + if let Some(v) = s.read_u64() { + if is_8digits(v) { + *x = x.wrapping_mul(1_0000_0000).wrapping_add(parse_8digits(v)); + // SAFETY: already ensured the buffer was >= 8 bytes in try_read_u64. + unsafe { + s.step_by(8); + } + } + } + } + } } -/// Checks if the input string is a valid floating point number and if so, locate the integral -/// part, the fractional part, and the exponent in it. Does not handle signs. -pub fn parse_decimal(s: &str) -> ParseResult<'_> { - if s.is_empty() { - return Invalid; +/// Parse the scientific notation component of a float. +fn parse_scientific(s: &mut AsciiStr<'_>) -> Option<i64> { + let mut exponent = 0_i64; + let mut negative = false; + if let Some(&c) = s.as_ref().get(0) { + negative = c == b'-'; + if c == b'-' || c == b'+' { + // SAFETY: s cannot be empty + unsafe { + s.step(); + } + } } + if s.first_isdigit() { + s.parse_digits(|digit| { + // no overflows here, saturate well before overflow + if exponent < 0x10000 { + exponent = 10 * exponent + digit as i64; + } + }); + if negative { Some(-exponent) } else { Some(exponent) } + } else { + None + } +} - let s = s.as_bytes(); - let (integral, s) = eat_digits(s); +/// Parse a partial, non-special floating point number. +/// +/// This creates a representation of the float as the +/// significant digits and the decimal exponent. +fn parse_partial_number(s: &[u8], negative: bool) -> Option<(Number, usize)> { + let mut s = AsciiStr::new(s); + let start = s; + debug_assert!(!s.is_empty()); - match s.first() { - None => Valid(Decimal::new(integral, b"", 0)), - Some(&b'e' | &b'E') => { - if integral.is_empty() { - return Invalid; // No digits before 'e' - } + // parse initial digits before dot + let mut mantissa = 0_u64; + let digits_start = s; + try_parse_digits(&mut s, &mut mantissa); + let mut n_digits = s.offset_from(&digits_start); + + // handle dot with the following digits + let mut n_after_dot = 0; + let mut exponent = 0_i64; + let int_end = s; + if s.first_is(b'.') { + // SAFETY: s cannot be empty due to first_is + unsafe { s.step() }; + let before = s; + try_parse_8digits(&mut s, &mut mantissa); + try_parse_digits(&mut s, &mut mantissa); + n_after_dot = s.offset_from(&before); + exponent = -n_after_dot as i64; + } - parse_exp(integral, b"", &s[1..]) + n_digits += n_after_dot; + if n_digits == 0 { + return None; + } + + // handle scientific format + let mut exp_number = 0_i64; + if s.first_is2(b'e', b'E') { + // SAFETY: s cannot be empty + unsafe { + s.step(); } - Some(&b'.') => { - let (fractional, s) = eat_digits(&s[1..]); - if integral.is_empty() && fractional.is_empty() { - // We require at least a single digit before or after the point. - return Invalid; - } + // If None, we have no trailing digits after exponent, or an invalid float. + exp_number = parse_scientific(&mut s)?; + exponent += exp_number; + } - match s.first() { - None => Valid(Decimal::new(integral, fractional, 0)), - Some(&b'e' | &b'E') => parse_exp(integral, fractional, &s[1..]), - _ => Invalid, // Trailing junk after fractional part - } + let len = s.offset_from(&start) as _; + + // handle uncommon case with many digits + if n_digits <= 19 { + return Some((Number { exponent, mantissa, negative, many_digits: false }, len)); + } + + n_digits -= 19; + let mut many_digits = false; + let mut p = digits_start; + while p.first_is2(b'0', b'.') { + // SAFETY: p cannot be empty due to first_is2 + unsafe { + // '0' = b'.' + 2 + n_digits -= p.first_unchecked().saturating_sub(b'0' - 1) as isize; + p.step(); } - _ => Invalid, // Trailing junk after first digit string } -} + if n_digits > 0 { + // at this point we have more than 19 significant digits, let's try again + many_digits = true; + mantissa = 0; + let mut s = digits_start; + try_parse_19digits(&mut s, &mut mantissa); + exponent = if mantissa >= MIN_19DIGIT_INT { + // big int + int_end.offset_from(&s) + } else { + // SAFETY: the next byte must be present and be '.' + // We know this is true because we had more than 19 + // digits previously, so we overflowed a 64-bit integer, + // but parsing only the integral digits produced less + // than 19 digits. That means we must have a decimal + // point, and at least 1 fractional digit. + unsafe { s.step() }; + let before = s; + try_parse_19digits(&mut s, &mut mantissa); + -s.offset_from(&before) + } as i64; + // add back the explicit part + exponent += exp_number; + } -/// Carves off decimal digits up to the first non-digit character. -fn eat_digits(s: &[u8]) -> (&[u8], &[u8]) { - let pos = s.iter().position(|c| !c.is_ascii_digit()).unwrap_or(s.len()); - s.split_at(pos) + Some((Number { exponent, mantissa, negative, many_digits }, len)) } -/// Exponent extraction and error checking. -fn parse_exp<'a>(integral: &'a [u8], fractional: &'a [u8], rest: &'a [u8]) -> ParseResult<'a> { - let (sign, rest) = match rest.first() { - Some(&b'-') => (Sign::Negative, &rest[1..]), - Some(&b'+') => (Sign::Positive, &rest[1..]), - _ => (Sign::Positive, rest), - }; - let (mut number, trailing) = eat_digits(rest); - if !trailing.is_empty() { - return Invalid; // Trailing junk after exponent +/// Try to parse a non-special floating point number. +pub fn parse_number(s: &[u8], negative: bool) -> Option<Number> { + if let Some((float, rest)) = parse_partial_number(s, negative) { + if rest == s.len() { + return Some(float); + } } - if number.is_empty() { - return Invalid; // Empty exponent + None +} + +/// Parse a partial representation of a special, non-finite float. +fn parse_partial_inf_nan<F: RawFloat>(s: &[u8]) -> Option<(F, usize)> { + fn parse_inf_rest(s: &[u8]) -> usize { + if s.len() >= 8 && s[3..].as_ref().eq_ignore_case(b"inity") { 8 } else { 3 } } - // At this point, we certainly have a valid string of digits. It may be too long to put into - // an `i64`, but if it's that huge, the input is certainly zero or infinity. Since each zero - // in the decimal digits only adjusts the exponent by +/- 1, at exp = 10^18 the input would - // have to be 17 exabyte (!) of zeros to get even remotely close to being finite. - // This is not exactly a use case we need to cater to. - while number.first() == Some(&b'0') { - number = &number[1..]; + if s.len() >= 3 { + if s.eq_ignore_case(b"nan") { + return Some((F::NAN, 3)); + } else if s.eq_ignore_case(b"inf") { + return Some((F::INFINITY, parse_inf_rest(s))); + } } - if number.len() >= 18 { - return match sign { - Sign::Positive => ShortcutToInf, - Sign::Negative => ShortcutToZero, - }; + None +} + +/// Try to parse a special, non-finite float. +pub fn parse_inf_nan<F: RawFloat>(s: &[u8], negative: bool) -> Option<F> { + if let Some((mut float, rest)) = parse_partial_inf_nan::<F>(s) { + if rest == s.len() { + if negative { + float = -float; + } + return Some(float); + } } - let abs_exp = num::from_str_unchecked(number); - let e = match sign { - Sign::Positive => abs_exp as i64, - Sign::Negative => -(abs_exp as i64), - }; - Valid(Decimal::new(integral, fractional, e)) + None } diff --git a/library/core/src/num/dec2flt/rawfp.rs b/library/core/src/num/dec2flt/rawfp.rs deleted file mode 100644 index 0ab15b23e53..00000000000 --- a/library/core/src/num/dec2flt/rawfp.rs +++ /dev/null @@ -1,363 +0,0 @@ -//! Bit fiddling on positive IEEE 754 floats. Negative numbers aren't and needn't be handled. -//! Normal floating point numbers have a canonical representation as (frac, exp) such that the -//! value is 2<sup>exp</sup> * (1 + sum(frac[N-i] / 2<sup>i</sup>)) where N is the number of bits. -//! Subnormals are slightly different and weird, but the same principle applies. -//! -//! Here, however, we represent them as (sig, k) with f positive, such that the value is f * -//! 2<sup>e</sup>. Besides making the "hidden bit" explicit, this changes the exponent by the -//! so-called mantissa shift. -//! -//! Put another way, normally floats are written as (1) but here they are written as (2): -//! -//! 1. `1.101100...11 * 2^m` -//! 2. `1101100...11 * 2^n` -//! -//! We call (1) the **fractional representation** and (2) the **integral representation**. -//! -//! Many functions in this module only handle normal numbers. The dec2flt routines conservatively -//! take the universally-correct slow path (Algorithm M) for very small and very large numbers. -//! That algorithm needs only next_float() which does handle subnormals and zeros. -use crate::cmp::Ordering::{Equal, Greater, Less}; -use crate::convert::{TryFrom, TryInto}; -use crate::fmt::{Debug, LowerExp}; -use crate::num::dec2flt::num::{self, Big}; -use crate::num::dec2flt::table; -use crate::num::diy_float::Fp; -use crate::num::FpCategory; -use crate::num::FpCategory::{Infinite, Nan, Normal, Subnormal, Zero}; -use crate::ops::{Add, Div, Mul, Neg}; - -#[derive(Copy, Clone, Debug)] -pub struct Unpacked { - pub sig: u64, - pub k: i16, -} - -impl Unpacked { - pub fn new(sig: u64, k: i16) -> Self { - Unpacked { sig, k } - } -} - -/// A helper trait to avoid duplicating basically all the conversion code for `f32` and `f64`. -/// -/// See the parent module's doc comment for why this is necessary. -/// -/// Should **never ever** be implemented for other types or be used outside the dec2flt module. -pub trait RawFloat: - Copy + Debug + LowerExp + Mul<Output = Self> + Div<Output = Self> + Neg<Output = Self> -{ - const INFINITY: Self; - const NAN: Self; - const ZERO: Self; - - /// Type used by `to_bits` and `from_bits`. - type Bits: Add<Output = Self::Bits> + From<u8> + TryFrom<u64>; - - /// Performs a raw transmutation to an integer. - fn to_bits(self) -> Self::Bits; - - /// Performs a raw transmutation from an integer. - fn from_bits(v: Self::Bits) -> Self; - - /// Returns the category that this number falls into. - fn classify(self) -> FpCategory; - - /// Returns the mantissa, exponent and sign as integers. - fn integer_decode(self) -> (u64, i16, i8); - - /// Decodes the float. - fn unpack(self) -> Unpacked; - - /// Casts from a small integer that can be represented exactly. Panic if the integer can't be - /// represented, the other code in this module makes sure to never let that happen. - fn from_int(x: u64) -> Self; - - /// Gets the value 10<sup>e</sup> from a pre-computed table. - /// Panics for `e >= CEIL_LOG5_OF_MAX_SIG`. - fn short_fast_pow10(e: usize) -> Self; - - /// What the name says. It's easier to hard code than juggling intrinsics and - /// hoping LLVM constant folds it. - const CEIL_LOG5_OF_MAX_SIG: i16; - - // A conservative bound on the decimal digits of inputs that can't produce overflow or zero or - /// subnormals. Probably the decimal exponent of the maximum normal value, hence the name. - const MAX_NORMAL_DIGITS: usize; - - /// When the most significant decimal digit has a place value greater than this, the number - /// is certainly rounded to infinity. - const INF_CUTOFF: i64; - - /// When the most significant decimal digit has a place value less than this, the number - /// is certainly rounded to zero. - const ZERO_CUTOFF: i64; - - /// The number of bits in the exponent. - const EXP_BITS: u8; - - /// The number of bits in the significand, *including* the hidden bit. - const SIG_BITS: u8; - - /// The number of bits in the significand, *excluding* the hidden bit. - const EXPLICIT_SIG_BITS: u8; - - /// The maximum legal exponent in fractional representation. - const MAX_EXP: i16; - - /// The minimum legal exponent in fractional representation, excluding subnormals. - const MIN_EXP: i16; - - /// `MAX_EXP` for integral representation, i.e., with the shift applied. - const MAX_EXP_INT: i16; - - /// `MAX_EXP` encoded (i.e., with offset bias) - const MAX_ENCODED_EXP: i16; - - /// `MIN_EXP` for integral representation, i.e., with the shift applied. - const MIN_EXP_INT: i16; - - /// The maximum normalized significand in integral representation. - const MAX_SIG: u64; - - /// The minimal normalized significand in integral representation. - const MIN_SIG: u64; -} - -// Mostly a workaround for #34344. -macro_rules! other_constants { - ($type: ident) => { - const EXPLICIT_SIG_BITS: u8 = Self::SIG_BITS - 1; - const MAX_EXP: i16 = (1 << (Self::EXP_BITS - 1)) - 1; - const MIN_EXP: i16 = -<Self as RawFloat>::MAX_EXP + 1; - const MAX_EXP_INT: i16 = <Self as RawFloat>::MAX_EXP - (Self::SIG_BITS as i16 - 1); - const MAX_ENCODED_EXP: i16 = (1 << Self::EXP_BITS) - 1; - const MIN_EXP_INT: i16 = <Self as RawFloat>::MIN_EXP - (Self::SIG_BITS as i16 - 1); - const MAX_SIG: u64 = (1 << Self::SIG_BITS) - 1; - const MIN_SIG: u64 = 1 << (Self::SIG_BITS - 1); - - const INFINITY: Self = $type::INFINITY; - const NAN: Self = $type::NAN; - const ZERO: Self = 0.0; - }; -} - -impl RawFloat for f32 { - type Bits = u32; - - const SIG_BITS: u8 = 24; - const EXP_BITS: u8 = 8; - const CEIL_LOG5_OF_MAX_SIG: i16 = 11; - const MAX_NORMAL_DIGITS: usize = 35; - const INF_CUTOFF: i64 = 40; - const ZERO_CUTOFF: i64 = -48; - other_constants!(f32); - - /// Returns the mantissa, exponent and sign as integers. - fn integer_decode(self) -> (u64, i16, i8) { - let bits = self.to_bits(); - let sign: i8 = if bits >> 31 == 0 { 1 } else { -1 }; - let mut exponent: i16 = ((bits >> 23) & 0xff) as i16; - let mantissa = - if exponent == 0 { (bits & 0x7fffff) << 1 } else { (bits & 0x7fffff) | 0x800000 }; - // Exponent bias + mantissa shift - exponent -= 127 + 23; - (mantissa as u64, exponent, sign) - } - - fn unpack(self) -> Unpacked { - let (sig, exp, _sig) = self.integer_decode(); - Unpacked::new(sig, exp) - } - - fn from_int(x: u64) -> f32 { - // rkruppe is uncertain whether `as` rounds correctly on all platforms. - debug_assert!(x as f32 == fp_to_float(Fp { f: x, e: 0 })); - x as f32 - } - - fn short_fast_pow10(e: usize) -> Self { - table::F32_SHORT_POWERS[e] - } - - fn classify(self) -> FpCategory { - self.classify() - } - fn to_bits(self) -> Self::Bits { - self.to_bits() - } - fn from_bits(v: Self::Bits) -> Self { - Self::from_bits(v) - } -} - -impl RawFloat for f64 { - type Bits = u64; - - const SIG_BITS: u8 = 53; - const EXP_BITS: u8 = 11; - const CEIL_LOG5_OF_MAX_SIG: i16 = 23; - const MAX_NORMAL_DIGITS: usize = 305; - const INF_CUTOFF: i64 = 310; - const ZERO_CUTOFF: i64 = -326; - other_constants!(f64); - - /// Returns the mantissa, exponent and sign as integers. - fn integer_decode(self) -> (u64, i16, i8) { - let bits = self.to_bits(); - let sign: i8 = if bits >> 63 == 0 { 1 } else { -1 }; - let mut exponent: i16 = ((bits >> 52) & 0x7ff) as i16; - let mantissa = if exponent == 0 { - (bits & 0xfffffffffffff) << 1 - } else { - (bits & 0xfffffffffffff) | 0x10000000000000 - }; - // Exponent bias + mantissa shift - exponent -= 1023 + 52; - (mantissa, exponent, sign) - } - - fn unpack(self) -> Unpacked { - let (sig, exp, _sig) = self.integer_decode(); - Unpacked::new(sig, exp) - } - - fn from_int(x: u64) -> f64 { - // rkruppe is uncertain whether `as` rounds correctly on all platforms. - debug_assert!(x as f64 == fp_to_float(Fp { f: x, e: 0 })); - x as f64 - } - - fn short_fast_pow10(e: usize) -> Self { - table::F64_SHORT_POWERS[e] - } - - fn classify(self) -> FpCategory { - self.classify() - } - fn to_bits(self) -> Self::Bits { - self.to_bits() - } - fn from_bits(v: Self::Bits) -> Self { - Self::from_bits(v) - } -} - -/// Converts an `Fp` to the closest machine float type. -/// Does not handle subnormal results. -pub fn fp_to_float<T: RawFloat>(x: Fp) -> T { - let x = x.normalize(); - // x.f is 64 bit, so x.e has a mantissa shift of 63 - let e = x.e + 63; - if e > T::MAX_EXP { - panic!("fp_to_float: exponent {} too large", e) - } else if e > T::MIN_EXP { - encode_normal(round_normal::<T>(x)) - } else { - panic!("fp_to_float: exponent {} too small", e) - } -} - -/// Round the 64-bit significand to T::SIG_BITS bits with half-to-even. -/// Does not handle exponent overflow. -pub fn round_normal<T: RawFloat>(x: Fp) -> Unpacked { - let excess = 64 - T::SIG_BITS as i16; - let half: u64 = 1 << (excess - 1); - let (q, rem) = (x.f >> excess, x.f & ((1 << excess) - 1)); - assert_eq!(q << excess | rem, x.f); - // Adjust mantissa shift - let k = x.e + excess; - if rem < half { - Unpacked::new(q, k) - } else if rem == half && (q % 2) == 0 { - Unpacked::new(q, k) - } else if q == T::MAX_SIG { - Unpacked::new(T::MIN_SIG, k + 1) - } else { - Unpacked::new(q + 1, k) - } -} - -/// Inverse of `RawFloat::unpack()` for normalized numbers. -/// Panics if the significand or exponent are not valid for normalized numbers. -pub fn encode_normal<T: RawFloat>(x: Unpacked) -> T { - debug_assert!( - T::MIN_SIG <= x.sig && x.sig <= T::MAX_SIG, - "encode_normal: significand not normalized" - ); - // Remove the hidden bit - let sig_enc = x.sig & !(1 << T::EXPLICIT_SIG_BITS); - // Adjust the exponent for exponent bias and mantissa shift - let k_enc = x.k + T::MAX_EXP + T::EXPLICIT_SIG_BITS as i16; - debug_assert!(k_enc != 0 && k_enc < T::MAX_ENCODED_EXP, "encode_normal: exponent out of range"); - // Leave sign bit at 0 ("+"), our numbers are all positive - let bits = (k_enc as u64) << T::EXPLICIT_SIG_BITS | sig_enc; - T::from_bits(bits.try_into().unwrap_or_else(|_| unreachable!())) -} - -/// Construct a subnormal. A mantissa of 0 is allowed and constructs zero. -pub fn encode_subnormal<T: RawFloat>(significand: u64) -> T { - assert!(significand < T::MIN_SIG, "encode_subnormal: not actually subnormal"); - // Encoded exponent is 0, the sign bit is 0, so we just have to reinterpret the bits. - T::from_bits(significand.try_into().unwrap_or_else(|_| unreachable!())) -} - -/// Approximate a bignum with an Fp. Rounds within 0.5 ULP with half-to-even. -pub fn big_to_fp(f: &Big) -> Fp { - let end = f.bit_length(); - assert!(end != 0, "big_to_fp: unexpectedly, input is zero"); - let start = end.saturating_sub(64); - let leading = num::get_bits(f, start, end); - // We cut off all bits prior to the index `start`, i.e., we effectively right-shift by - // an amount of `start`, so this is also the exponent we need. - let e = start as i16; - let rounded_down = Fp { f: leading, e }.normalize(); - // Round (half-to-even) depending on the truncated bits. - match num::compare_with_half_ulp(f, start) { - Less => rounded_down, - Equal if leading % 2 == 0 => rounded_down, - Equal | Greater => match leading.checked_add(1) { - Some(f) => Fp { f, e }.normalize(), - None => Fp { f: 1 << 63, e: e + 1 }, - }, - } -} - -/// Finds the largest floating point number strictly smaller than the argument. -/// Does not handle subnormals, zero, or exponent underflow. -pub fn prev_float<T: RawFloat>(x: T) -> T { - match x.classify() { - Infinite => panic!("prev_float: argument is infinite"), - Nan => panic!("prev_float: argument is NaN"), - Subnormal => panic!("prev_float: argument is subnormal"), - Zero => panic!("prev_float: argument is zero"), - Normal => { - let Unpacked { sig, k } = x.unpack(); - if sig == T::MIN_SIG { - encode_normal(Unpacked::new(T::MAX_SIG, k - 1)) - } else { - encode_normal(Unpacked::new(sig - 1, k)) - } - } - } -} - -// Find the smallest floating point number strictly larger than the argument. -// This operation is saturating, i.e., next_float(inf) == inf. -// Unlike most code in this module, this function does handle zero, subnormals, and infinities. -// However, like all other code here, it does not deal with NaN and negative numbers. -pub fn next_float<T: RawFloat>(x: T) -> T { - match x.classify() { - Nan => panic!("next_float: argument is NaN"), - Infinite => T::INFINITY, - // This seems too good to be true, but it works. - // 0.0 is encoded as the all-zero word. Subnormals are 0x000m...m where m is the mantissa. - // In particular, the smallest subnormal is 0x0...01 and the largest is 0x000F...F. - // The smallest normal number is 0x0010...0, so this corner case works as well. - // If the increment overflows the mantissa, the carry bit increments the exponent as we - // want, and the mantissa bits become zero. Because of the hidden bit convention, this - // too is exactly what we want! - // Finally, f64::MAX + 1 = 7eff...f + 1 = 7ff0...0 = f64::INFINITY. - Zero | Subnormal | Normal => T::from_bits(x.to_bits() + T::Bits::from(1u8)), - } -} diff --git a/library/core/src/num/dec2flt/slow.rs b/library/core/src/num/dec2flt/slow.rs new file mode 100644 index 00000000000..bf1044033e6 --- /dev/null +++ b/library/core/src/num/dec2flt/slow.rs @@ -0,0 +1,109 @@ +//! Slow, fallback algorithm for cases the Eisel-Lemire algorithm cannot round. + +use crate::num::dec2flt::common::BiasedFp; +use crate::num::dec2flt::decimal::{parse_decimal, Decimal}; +use crate::num::dec2flt::float::RawFloat; + +/// Parse the significant digits and biased, binary exponent of a float. +/// +/// This is a fallback algorithm that uses a big-integer representation +/// of the float, and therefore is considerably slower than faster +/// approximations. However, it will always determine how to round +/// the significant digits to the nearest machine float, allowing +/// use to handle near half-way cases. +/// +/// Near half-way cases are halfway between two consecutive machine floats. +/// For example, the float `16777217.0` has a bitwise representation of +/// `100000000000000000000000 1`. Rounding to a single-precision float, +/// the trailing `1` is truncated. Using round-nearest, tie-even, any +/// value above `16777217.0` must be rounded up to `16777218.0`, while +/// any value before or equal to `16777217.0` must be rounded down +/// to `16777216.0`. These near-halfway conversions therefore may require +/// a large number of digits to unambiguously determine how to round. +/// +/// The algorithms described here are based on "Processing Long Numbers Quickly", +/// available here: <https://arxiv.org/pdf/2101.11408.pdf#section.11>. +pub(crate) fn parse_long_mantissa<F: RawFloat>(s: &[u8]) -> BiasedFp { + const MAX_SHIFT: usize = 60; + const NUM_POWERS: usize = 19; + const POWERS: [u8; 19] = + [0, 3, 6, 9, 13, 16, 19, 23, 26, 29, 33, 36, 39, 43, 46, 49, 53, 56, 59]; + + let get_shift = |n| { + if n < NUM_POWERS { POWERS[n] as usize } else { MAX_SHIFT } + }; + + let fp_zero = BiasedFp::zero_pow2(0); + let fp_inf = BiasedFp::zero_pow2(F::INFINITE_POWER); + + let mut d = parse_decimal(s); + + // Short-circuit if the value can only be a literal 0 or infinity. + if d.num_digits == 0 || d.decimal_point < -324 { + return fp_zero; + } else if d.decimal_point >= 310 { + return fp_inf; + } + let mut exp2 = 0_i32; + // Shift right toward (1/2 ... 1]. + while d.decimal_point > 0 { + let n = d.decimal_point as usize; + let shift = get_shift(n); + d.right_shift(shift); + if d.decimal_point < -Decimal::DECIMAL_POINT_RANGE { + return fp_zero; + } + exp2 += shift as i32; + } + // Shift left toward (1/2 ... 1]. + while d.decimal_point <= 0 { + let shift = if d.decimal_point == 0 { + match d.digits[0] { + digit if digit >= 5 => break, + 0 | 1 => 2, + _ => 1, + } + } else { + get_shift((-d.decimal_point) as _) + }; + d.left_shift(shift); + if d.decimal_point > Decimal::DECIMAL_POINT_RANGE { + return fp_inf; + } + exp2 -= shift as i32; + } + // We are now in the range [1/2 ... 1] but the binary format uses [1 ... 2]. + exp2 -= 1; + while (F::MINIMUM_EXPONENT + 1) > exp2 { + let mut n = ((F::MINIMUM_EXPONENT + 1) - exp2) as usize; + if n > MAX_SHIFT { + n = MAX_SHIFT; + } + d.right_shift(n); + exp2 += n as i32; + } + if (exp2 - F::MINIMUM_EXPONENT) >= F::INFINITE_POWER { + return fp_inf; + } + // Shift the decimal to the hidden bit, and then round the value + // to get the high mantissa+1 bits. + d.left_shift(F::MANTISSA_EXPLICIT_BITS + 1); + let mut mantissa = d.round(); + if mantissa >= (1_u64 << (F::MANTISSA_EXPLICIT_BITS + 1)) { + // Rounding up overflowed to the carry bit, need to + // shift back to the hidden bit. + d.right_shift(1); + exp2 += 1; + mantissa = d.round(); + if (exp2 - F::MINIMUM_EXPONENT) >= F::INFINITE_POWER { + return fp_inf; + } + } + let mut power2 = exp2 - F::MINIMUM_EXPONENT; + if mantissa < (1_u64 << F::MANTISSA_EXPLICIT_BITS) { + power2 -= 1; + } + // Zero out all the bits above the explicit mantissa bits. + mantissa &= (1_u64 << F::MANTISSA_EXPLICIT_BITS) - 1; + BiasedFp { f: mantissa, e: power2 } +} diff --git a/library/core/src/num/dec2flt/table.rs b/library/core/src/num/dec2flt/table.rs index 97b497e81e0..4856074a62b 100644 --- a/library/core/src/num/dec2flt/table.rs +++ b/library/core/src/num/dec2flt/table.rs @@ -1,1277 +1,670 @@ -//! Tables of approximations of powers of ten. +//! Pre-computed tables powers-of-5 for extended-precision representations. +//! +//! These tables enable fast scaling of the significant digits +//! of a float to the decimal exponent, with minimal rounding +//! errors, in a 128 or 192-bit representation. +//! //! DO NOT MODIFY: Generated by `src/etc/dec2flt_table.py` -pub const MIN_E: i16 = -305; -pub const MAX_E: i16 = 305; +pub const SMALLEST_POWER_OF_FIVE: i32 = -342; +pub const LARGEST_POWER_OF_FIVE: i32 = 308; +pub const N_POWERS_OF_FIVE: usize = (LARGEST_POWER_OF_FIVE - SMALLEST_POWER_OF_FIVE + 1) as usize; +// Use static to avoid long compile times: Rust compiler errors +// can have the entire table compiled multiple times, and then +// emit code multiple times, even if it's stripped out in +// the final binary. #[rustfmt::skip] -pub static POWERS: ([u64; 611], [i16; 611]) = ( - [ - 0xe0b62e2929aba83c, - 0x8c71dcd9ba0b4926, - 0xaf8e5410288e1b6f, - 0xdb71e91432b1a24b, - 0x892731ac9faf056f, - 0xab70fe17c79ac6ca, - 0xd64d3d9db981787d, - 0x85f0468293f0eb4e, - 0xa76c582338ed2622, - 0xd1476e2c07286faa, - 0x82cca4db847945ca, - 0xa37fce126597973d, - 0xcc5fc196fefd7d0c, - 0xff77b1fcbebcdc4f, - 0x9faacf3df73609b1, - 0xc795830d75038c1e, - 0xf97ae3d0d2446f25, - 0x9becce62836ac577, - 0xc2e801fb244576d5, - 0xf3a20279ed56d48a, - 0x9845418c345644d7, - 0xbe5691ef416bd60c, - 0xedec366b11c6cb8f, - 0x94b3a202eb1c3f39, - 0xb9e08a83a5e34f08, - 0xe858ad248f5c22ca, - 0x91376c36d99995be, - 0xb58547448ffffb2e, - 0xe2e69915b3fff9f9, - 0x8dd01fad907ffc3c, - 0xb1442798f49ffb4b, - 0xdd95317f31c7fa1d, - 0x8a7d3eef7f1cfc52, - 0xad1c8eab5ee43b67, - 0xd863b256369d4a41, - 0x873e4f75e2224e68, - 0xa90de3535aaae202, - 0xd3515c2831559a83, - 0x8412d9991ed58092, - 0xa5178fff668ae0b6, - 0xce5d73ff402d98e4, - 0x80fa687f881c7f8e, - 0xa139029f6a239f72, - 0xc987434744ac874f, - 0xfbe9141915d7a922, - 0x9d71ac8fada6c9b5, - 0xc4ce17b399107c23, - 0xf6019da07f549b2b, - 0x99c102844f94e0fb, - 0xc0314325637a193a, - 0xf03d93eebc589f88, - 0x96267c7535b763b5, - 0xbbb01b9283253ca3, - 0xea9c227723ee8bcb, - 0x92a1958a7675175f, - 0xb749faed14125d37, - 0xe51c79a85916f485, - 0x8f31cc0937ae58d3, - 0xb2fe3f0b8599ef08, - 0xdfbdcece67006ac9, - 0x8bd6a141006042be, - 0xaecc49914078536d, - 0xda7f5bf590966849, - 0x888f99797a5e012d, - 0xaab37fd7d8f58179, - 0xd5605fcdcf32e1d7, - 0x855c3be0a17fcd26, - 0xa6b34ad8c9dfc070, - 0xd0601d8efc57b08c, - 0x823c12795db6ce57, - 0xa2cb1717b52481ed, - 0xcb7ddcdda26da269, - 0xfe5d54150b090b03, - 0x9efa548d26e5a6e2, - 0xc6b8e9b0709f109a, - 0xf867241c8cc6d4c1, - 0x9b407691d7fc44f8, - 0xc21094364dfb5637, - 0xf294b943e17a2bc4, - 0x979cf3ca6cec5b5b, - 0xbd8430bd08277231, - 0xece53cec4a314ebe, - 0x940f4613ae5ed137, - 0xb913179899f68584, - 0xe757dd7ec07426e5, - 0x9096ea6f3848984f, - 0xb4bca50b065abe63, - 0xe1ebce4dc7f16dfc, - 0x8d3360f09cf6e4bd, - 0xb080392cc4349ded, - 0xdca04777f541c568, - 0x89e42caaf9491b61, - 0xac5d37d5b79b6239, - 0xd77485cb25823ac7, - 0x86a8d39ef77164bd, - 0xa8530886b54dbdec, - 0xd267caa862a12d67, - 0x8380dea93da4bc60, - 0xa46116538d0deb78, - 0xcd795be870516656, - 0x806bd9714632dff6, - 0xa086cfcd97bf97f4, - 0xc8a883c0fdaf7df0, - 0xfad2a4b13d1b5d6c, - 0x9cc3a6eec6311a64, - 0xc3f490aa77bd60fd, - 0xf4f1b4d515acb93c, - 0x991711052d8bf3c5, - 0xbf5cd54678eef0b7, - 0xef340a98172aace5, - 0x9580869f0e7aac0f, - 0xbae0a846d2195713, - 0xe998d258869facd7, - 0x91ff83775423cc06, - 0xb67f6455292cbf08, - 0xe41f3d6a7377eeca, - 0x8e938662882af53e, - 0xb23867fb2a35b28e, - 0xdec681f9f4c31f31, - 0x8b3c113c38f9f37f, - 0xae0b158b4738705f, - 0xd98ddaee19068c76, - 0x87f8a8d4cfa417ca, - 0xa9f6d30a038d1dbc, - 0xd47487cc8470652b, - 0x84c8d4dfd2c63f3b, - 0xa5fb0a17c777cf0a, - 0xcf79cc9db955c2cc, - 0x81ac1fe293d599c0, - 0xa21727db38cb0030, - 0xca9cf1d206fdc03c, - 0xfd442e4688bd304b, - 0x9e4a9cec15763e2f, - 0xc5dd44271ad3cdba, - 0xf7549530e188c129, - 0x9a94dd3e8cf578ba, - 0xc13a148e3032d6e8, - 0xf18899b1bc3f8ca2, - 0x96f5600f15a7b7e5, - 0xbcb2b812db11a5de, - 0xebdf661791d60f56, - 0x936b9fcebb25c996, - 0xb84687c269ef3bfb, - 0xe65829b3046b0afa, - 0x8ff71a0fe2c2e6dc, - 0xb3f4e093db73a093, - 0xe0f218b8d25088b8, - 0x8c974f7383725573, - 0xafbd2350644eead0, - 0xdbac6c247d62a584, - 0x894bc396ce5da772, - 0xab9eb47c81f5114f, - 0xd686619ba27255a3, - 0x8613fd0145877586, - 0xa798fc4196e952e7, - 0xd17f3b51fca3a7a1, - 0x82ef85133de648c5, - 0xa3ab66580d5fdaf6, - 0xcc963fee10b7d1b3, - 0xffbbcfe994e5c620, - 0x9fd561f1fd0f9bd4, - 0xc7caba6e7c5382c9, - 0xf9bd690a1b68637b, - 0x9c1661a651213e2d, - 0xc31bfa0fe5698db8, - 0xf3e2f893dec3f126, - 0x986ddb5c6b3a76b8, - 0xbe89523386091466, - 0xee2ba6c0678b597f, - 0x94db483840b717f0, - 0xba121a4650e4ddec, - 0xe896a0d7e51e1566, - 0x915e2486ef32cd60, - 0xb5b5ada8aaff80b8, - 0xe3231912d5bf60e6, - 0x8df5efabc5979c90, - 0xb1736b96b6fd83b4, - 0xddd0467c64bce4a1, - 0x8aa22c0dbef60ee4, - 0xad4ab7112eb3929e, - 0xd89d64d57a607745, - 0x87625f056c7c4a8b, - 0xa93af6c6c79b5d2e, - 0xd389b47879823479, - 0x843610cb4bf160cc, - 0xa54394fe1eedb8ff, - 0xce947a3da6a9273e, - 0x811ccc668829b887, - 0xa163ff802a3426a9, - 0xc9bcff6034c13053, - 0xfc2c3f3841f17c68, - 0x9d9ba7832936edc1, - 0xc5029163f384a931, - 0xf64335bcf065d37d, - 0x99ea0196163fa42e, - 0xc06481fb9bcf8d3a, - 0xf07da27a82c37088, - 0x964e858c91ba2655, - 0xbbe226efb628afeb, - 0xeadab0aba3b2dbe5, - 0x92c8ae6b464fc96f, - 0xb77ada0617e3bbcb, - 0xe55990879ddcaabe, - 0x8f57fa54c2a9eab7, - 0xb32df8e9f3546564, - 0xdff9772470297ebd, - 0x8bfbea76c619ef36, - 0xaefae51477a06b04, - 0xdab99e59958885c5, - 0x88b402f7fd75539b, - 0xaae103b5fcd2a882, - 0xd59944a37c0752a2, - 0x857fcae62d8493a5, - 0xa6dfbd9fb8e5b88f, - 0xd097ad07a71f26b2, - 0x825ecc24c8737830, - 0xa2f67f2dfa90563b, - 0xcbb41ef979346bca, - 0xfea126b7d78186bd, - 0x9f24b832e6b0f436, - 0xc6ede63fa05d3144, - 0xf8a95fcf88747d94, - 0x9b69dbe1b548ce7d, - 0xc24452da229b021c, - 0xf2d56790ab41c2a3, - 0x97c560ba6b0919a6, - 0xbdb6b8e905cb600f, - 0xed246723473e3813, - 0x9436c0760c86e30c, - 0xb94470938fa89bcf, - 0xe7958cb87392c2c3, - 0x90bd77f3483bb9ba, - 0xb4ecd5f01a4aa828, - 0xe2280b6c20dd5232, - 0x8d590723948a535f, - 0xb0af48ec79ace837, - 0xdcdb1b2798182245, - 0x8a08f0f8bf0f156b, - 0xac8b2d36eed2dac6, - 0xd7adf884aa879177, - 0x86ccbb52ea94baeb, - 0xa87fea27a539e9a5, - 0xd29fe4b18e88640f, - 0x83a3eeeef9153e89, - 0xa48ceaaab75a8e2b, - 0xcdb02555653131b6, - 0x808e17555f3ebf12, - 0xa0b19d2ab70e6ed6, - 0xc8de047564d20a8c, - 0xfb158592be068d2f, - 0x9ced737bb6c4183d, - 0xc428d05aa4751e4d, - 0xf53304714d9265e0, - 0x993fe2c6d07b7fac, - 0xbf8fdb78849a5f97, - 0xef73d256a5c0f77d, - 0x95a8637627989aae, - 0xbb127c53b17ec159, - 0xe9d71b689dde71b0, - 0x9226712162ab070e, - 0xb6b00d69bb55c8d1, - 0xe45c10c42a2b3b06, - 0x8eb98a7a9a5b04e3, - 0xb267ed1940f1c61c, - 0xdf01e85f912e37a3, - 0x8b61313bbabce2c6, - 0xae397d8aa96c1b78, - 0xd9c7dced53c72256, - 0x881cea14545c7575, - 0xaa242499697392d3, - 0xd4ad2dbfc3d07788, - 0x84ec3c97da624ab5, - 0xa6274bbdd0fadd62, - 0xcfb11ead453994ba, - 0x81ceb32c4b43fcf5, - 0xa2425ff75e14fc32, - 0xcad2f7f5359a3b3e, - 0xfd87b5f28300ca0e, - 0x9e74d1b791e07e48, - 0xc612062576589ddb, - 0xf79687aed3eec551, - 0x9abe14cd44753b53, - 0xc16d9a0095928a27, - 0xf1c90080baf72cb1, - 0x971da05074da7bef, - 0xbce5086492111aeb, - 0xec1e4a7db69561a5, - 0x9392ee8e921d5d07, - 0xb877aa3236a4b449, - 0xe69594bec44de15b, - 0x901d7cf73ab0acd9, - 0xb424dc35095cd80f, - 0xe12e13424bb40e13, - 0x8cbccc096f5088cc, - 0xafebff0bcb24aaff, - 0xdbe6fecebdedd5bf, - 0x89705f4136b4a597, - 0xabcc77118461cefd, - 0xd6bf94d5e57a42bc, - 0x8637bd05af6c69b6, - 0xa7c5ac471b478423, - 0xd1b71758e219652c, - 0x83126e978d4fdf3b, - 0xa3d70a3d70a3d70a, - 0xcccccccccccccccd, - 0x8000000000000000, - 0xa000000000000000, - 0xc800000000000000, - 0xfa00000000000000, - 0x9c40000000000000, - 0xc350000000000000, - 0xf424000000000000, - 0x9896800000000000, - 0xbebc200000000000, - 0xee6b280000000000, - 0x9502f90000000000, - 0xba43b74000000000, - 0xe8d4a51000000000, - 0x9184e72a00000000, - 0xb5e620f480000000, - 0xe35fa931a0000000, - 0x8e1bc9bf04000000, - 0xb1a2bc2ec5000000, - 0xde0b6b3a76400000, - 0x8ac7230489e80000, - 0xad78ebc5ac620000, - 0xd8d726b7177a8000, - 0x878678326eac9000, - 0xa968163f0a57b400, - 0xd3c21bcecceda100, - 0x84595161401484a0, - 0xa56fa5b99019a5c8, - 0xcecb8f27f4200f3a, - 0x813f3978f8940984, - 0xa18f07d736b90be5, - 0xc9f2c9cd04674edf, - 0xfc6f7c4045812296, - 0x9dc5ada82b70b59e, - 0xc5371912364ce305, - 0xf684df56c3e01bc7, - 0x9a130b963a6c115c, - 0xc097ce7bc90715b3, - 0xf0bdc21abb48db20, - 0x96769950b50d88f4, - 0xbc143fa4e250eb31, - 0xeb194f8e1ae525fd, - 0x92efd1b8d0cf37be, - 0xb7abc627050305ae, - 0xe596b7b0c643c719, - 0x8f7e32ce7bea5c70, - 0xb35dbf821ae4f38c, - 0xe0352f62a19e306f, - 0x8c213d9da502de45, - 0xaf298d050e4395d7, - 0xdaf3f04651d47b4c, - 0x88d8762bf324cd10, - 0xab0e93b6efee0054, - 0xd5d238a4abe98068, - 0x85a36366eb71f041, - 0xa70c3c40a64e6c52, - 0xd0cf4b50cfe20766, - 0x82818f1281ed44a0, - 0xa321f2d7226895c8, - 0xcbea6f8ceb02bb3a, - 0xfee50b7025c36a08, - 0x9f4f2726179a2245, - 0xc722f0ef9d80aad6, - 0xf8ebad2b84e0d58c, - 0x9b934c3b330c8577, - 0xc2781f49ffcfa6d5, - 0xf316271c7fc3908b, - 0x97edd871cfda3a57, - 0xbde94e8e43d0c8ec, - 0xed63a231d4c4fb27, - 0x945e455f24fb1cf9, - 0xb975d6b6ee39e437, - 0xe7d34c64a9c85d44, - 0x90e40fbeea1d3a4b, - 0xb51d13aea4a488dd, - 0xe264589a4dcdab15, - 0x8d7eb76070a08aed, - 0xb0de65388cc8ada8, - 0xdd15fe86affad912, - 0x8a2dbf142dfcc7ab, - 0xacb92ed9397bf996, - 0xd7e77a8f87daf7fc, - 0x86f0ac99b4e8dafd, - 0xa8acd7c0222311bd, - 0xd2d80db02aabd62c, - 0x83c7088e1aab65db, - 0xa4b8cab1a1563f52, - 0xcde6fd5e09abcf27, - 0x80b05e5ac60b6178, - 0xa0dc75f1778e39d6, - 0xc913936dd571c84c, - 0xfb5878494ace3a5f, - 0x9d174b2dcec0e47b, - 0xc45d1df942711d9a, - 0xf5746577930d6501, - 0x9968bf6abbe85f20, - 0xbfc2ef456ae276e9, - 0xefb3ab16c59b14a3, - 0x95d04aee3b80ece6, - 0xbb445da9ca61281f, - 0xea1575143cf97227, - 0x924d692ca61be758, - 0xb6e0c377cfa2e12e, - 0xe498f455c38b997a, - 0x8edf98b59a373fec, - 0xb2977ee300c50fe7, - 0xdf3d5e9bc0f653e1, - 0x8b865b215899f46d, - 0xae67f1e9aec07188, - 0xda01ee641a708dea, - 0x884134fe908658b2, - 0xaa51823e34a7eedf, - 0xd4e5e2cdc1d1ea96, - 0x850fadc09923329e, - 0xa6539930bf6bff46, - 0xcfe87f7cef46ff17, - 0x81f14fae158c5f6e, - 0xa26da3999aef774a, - 0xcb090c8001ab551c, - 0xfdcb4fa002162a63, - 0x9e9f11c4014dda7e, - 0xc646d63501a1511e, - 0xf7d88bc24209a565, - 0x9ae757596946075f, - 0xc1a12d2fc3978937, - 0xf209787bb47d6b85, - 0x9745eb4d50ce6333, - 0xbd176620a501fc00, - 0xec5d3fa8ce427b00, - 0x93ba47c980e98ce0, - 0xb8a8d9bbe123f018, - 0xe6d3102ad96cec1e, - 0x9043ea1ac7e41393, - 0xb454e4a179dd1877, - 0xe16a1dc9d8545e95, - 0x8ce2529e2734bb1d, - 0xb01ae745b101e9e4, - 0xdc21a1171d42645d, - 0x899504ae72497eba, - 0xabfa45da0edbde69, - 0xd6f8d7509292d603, - 0x865b86925b9bc5c2, - 0xa7f26836f282b733, - 0xd1ef0244af2364ff, - 0x8335616aed761f1f, - 0xa402b9c5a8d3a6e7, - 0xcd036837130890a1, - 0x802221226be55a65, - 0xa02aa96b06deb0fe, - 0xc83553c5c8965d3d, - 0xfa42a8b73abbf48d, - 0x9c69a97284b578d8, - 0xc38413cf25e2d70e, - 0xf46518c2ef5b8cd1, - 0x98bf2f79d5993803, - 0xbeeefb584aff8604, - 0xeeaaba2e5dbf6785, - 0x952ab45cfa97a0b3, - 0xba756174393d88e0, - 0xe912b9d1478ceb17, - 0x91abb422ccb812ef, - 0xb616a12b7fe617aa, - 0xe39c49765fdf9d95, - 0x8e41ade9fbebc27d, - 0xb1d219647ae6b31c, - 0xde469fbd99a05fe3, - 0x8aec23d680043bee, - 0xada72ccc20054aea, - 0xd910f7ff28069da4, - 0x87aa9aff79042287, - 0xa99541bf57452b28, - 0xd3fa922f2d1675f2, - 0x847c9b5d7c2e09b7, - 0xa59bc234db398c25, - 0xcf02b2c21207ef2f, - 0x8161afb94b44f57d, - 0xa1ba1ba79e1632dc, - 0xca28a291859bbf93, - 0xfcb2cb35e702af78, - 0x9defbf01b061adab, - 0xc56baec21c7a1916, - 0xf6c69a72a3989f5c, - 0x9a3c2087a63f6399, - 0xc0cb28a98fcf3c80, - 0xf0fdf2d3f3c30b9f, - 0x969eb7c47859e744, - 0xbc4665b596706115, - 0xeb57ff22fc0c795a, - 0x9316ff75dd87cbd8, - 0xb7dcbf5354e9bece, - 0xe5d3ef282a242e82, - 0x8fa475791a569d11, - 0xb38d92d760ec4455, - 0xe070f78d3927556b, - 0x8c469ab843b89563, - 0xaf58416654a6babb, - 0xdb2e51bfe9d0696a, - 0x88fcf317f22241e2, - 0xab3c2fddeeaad25b, - 0xd60b3bd56a5586f2, - 0x85c7056562757457, - 0xa738c6bebb12d16d, - 0xd106f86e69d785c8, - 0x82a45b450226b39d, - 0xa34d721642b06084, - 0xcc20ce9bd35c78a5, - 0xff290242c83396ce, - 0x9f79a169bd203e41, - 0xc75809c42c684dd1, - 0xf92e0c3537826146, - 0x9bbcc7a142b17ccc, - 0xc2abf989935ddbfe, - 0xf356f7ebf83552fe, - 0x98165af37b2153df, - 0xbe1bf1b059e9a8d6, - 0xeda2ee1c7064130c, - 0x9485d4d1c63e8be8, - 0xb9a74a0637ce2ee1, - 0xe8111c87c5c1ba9a, - 0x910ab1d4db9914a0, - 0xb54d5e4a127f59c8, - 0xe2a0b5dc971f303a, - 0x8da471a9de737e24, - 0xb10d8e1456105dad, - 0xdd50f1996b947519, - 0x8a5296ffe33cc930, - 0xace73cbfdc0bfb7b, - 0xd8210befd30efa5a, - 0x8714a775e3e95c78, - 0xa8d9d1535ce3b396, - 0xd31045a8341ca07c, - 0x83ea2b892091e44e, - 0xa4e4b66b68b65d61, - 0xce1de40642e3f4b9, - 0x80d2ae83e9ce78f4, - 0xa1075a24e4421731, - 0xc94930ae1d529cfd, - 0xfb9b7cd9a4a7443c, - 0x9d412e0806e88aa6, - 0xc491798a08a2ad4f, - 0xf5b5d7ec8acb58a3, - 0x9991a6f3d6bf1766, - 0xbff610b0cc6edd3f, - 0xeff394dcff8a948f, - 0x95f83d0a1fb69cd9, - 0xbb764c4ca7a44410, - 0xea53df5fd18d5514, - 0x92746b9be2f8552c, - 0xb7118682dbb66a77, - 0xe4d5e82392a40515, - 0x8f05b1163ba6832d, - 0xb2c71d5bca9023f8, - 0xdf78e4b2bd342cf7, - 0x8bab8eefb6409c1a, - 0xae9672aba3d0c321, - 0xda3c0f568cc4f3e9, - 0x8865899617fb1871, - 0xaa7eebfb9df9de8e, - 0xd51ea6fa85785631, - 0x8533285c936b35df, - 0xa67ff273b8460357, - 0xd01fef10a657842c, - 0x8213f56a67f6b29c, - 0xa298f2c501f45f43, - 0xcb3f2f7642717713, - 0xfe0efb53d30dd4d8, - 0x9ec95d1463e8a507, - 0xc67bb4597ce2ce49, - 0xf81aa16fdc1b81db, - 0x9b10a4e5e9913129, - 0xc1d4ce1f63f57d73, - 0xf24a01a73cf2dcd0, - 0x976e41088617ca02, - 0xbd49d14aa79dbc82, - 0xec9c459d51852ba3, - 0x93e1ab8252f33b46, - 0xb8da1662e7b00a17, - 0xe7109bfba19c0c9d, - 0x906a617d450187e2, - 0xb484f9dc9641e9db, - 0xe1a63853bbd26451, - 0x8d07e33455637eb3, - 0xb049dc016abc5e60, - 0xdc5c5301c56b75f7, - 0x89b9b3e11b6329bb, - 0xac2820d9623bf429, - 0xd732290fbacaf134, - 0x867f59a9d4bed6c0, - 0xa81f301449ee8c70, - 0xd226fc195c6a2f8c, - 0x83585d8fd9c25db8, - 0xa42e74f3d032f526, - 0xcd3a1230c43fb26f, - 0x80444b5e7aa7cf85, - 0xa0555e361951c367, - 0xc86ab5c39fa63441, - 0xfa856334878fc151, - 0x9c935e00d4b9d8d2, - 0xc3b8358109e84f07, - 0xf4a642e14c6262c9, - 0x98e7e9cccfbd7dbe, - 0xbf21e44003acdd2d, - 0xeeea5d5004981478, - 0x95527a5202df0ccb, - 0xbaa718e68396cffe, - 0xe950df20247c83fd, - 0x91d28b7416cdd27e, - ], - [ - -1077, - -1073, - -1070, - -1067, - -1063, - -1060, - -1057, - -1053, - -1050, - -1047, - -1043, - -1040, - -1037, - -1034, - -1030, - -1027, - -1024, - -1020, - -1017, - -1014, - -1010, - -1007, - -1004, - -1000, - -997, - -994, - -990, - -987, - -984, - -980, - -977, - -974, - -970, - -967, - -964, - -960, - -957, - -954, - -950, - -947, - -944, - -940, - -937, - -934, - -931, - -927, - -924, - -921, - -917, - -914, - -911, - -907, - -904, - -901, - -897, - -894, - -891, - -887, - -884, - -881, - -877, - -874, - -871, - -867, - -864, - -861, - -857, - -854, - -851, - -847, - -844, - -841, - -838, - -834, - -831, - -828, - -824, - -821, - -818, - -814, - -811, - -808, - -804, - -801, - -798, - -794, - -791, - -788, - -784, - -781, - -778, - -774, - -771, - -768, - -764, - -761, - -758, - -754, - -751, - -748, - -744, - -741, - -738, - -735, - -731, - -728, - -725, - -721, - -718, - -715, - -711, - -708, - -705, - -701, - -698, - -695, - -691, - -688, - -685, - -681, - -678, - -675, - -671, - -668, - -665, - -661, - -658, - -655, - -651, - -648, - -645, - -642, - -638, - -635, - -632, - -628, - -625, - -622, - -618, - -615, - -612, - -608, - -605, - -602, - -598, - -595, - -592, - -588, - -585, - -582, - -578, - -575, - -572, - -568, - -565, - -562, - -558, - -555, - -552, - -549, - -545, - -542, - -539, - -535, - -532, - -529, - -525, - -522, - -519, - -515, - -512, - -509, - -505, - -502, - -499, - -495, - -492, - -489, - -485, - -482, - -479, - -475, - -472, - -469, - -465, - -462, - -459, - -455, - -452, - -449, - -446, - -442, - -439, - -436, - -432, - -429, - -426, - -422, - -419, - -416, - -412, - -409, - -406, - -402, - -399, - -396, - -392, - -389, - -386, - -382, - -379, - -376, - -372, - -369, - -366, - -362, - -359, - -356, - -353, - -349, - -346, - -343, - -339, - -336, - -333, - -329, - -326, - -323, - -319, - -316, - -313, - -309, - -306, - -303, - -299, - -296, - -293, - -289, - -286, - -283, - -279, - -276, - -273, - -269, - -266, - -263, - -259, - -256, - -253, - -250, - -246, - -243, - -240, - -236, - -233, - -230, - -226, - -223, - -220, - -216, - -213, - -210, - -206, - -203, - -200, - -196, - -193, - -190, - -186, - -183, - -180, - -176, - -173, - -170, - -166, - -163, - -160, - -157, - -153, - -150, - -147, - -143, - -140, - -137, - -133, - -130, - -127, - -123, - -120, - -117, - -113, - -110, - -107, - -103, - -100, - -97, - -93, - -90, - -87, - -83, - -80, - -77, - -73, - -70, - -67, - -63, - -60, - -57, - -54, - -50, - -47, - -44, - -40, - -37, - -34, - -30, - -27, - -24, - -20, - -17, - -14, - -10, - -7, - -4, - 0, - 3, - 6, - 10, - 13, - 16, - 20, - 23, - 26, - 30, - 33, - 36, - 39, - 43, - 46, - 49, - 53, - 56, - 59, - 63, - 66, - 69, - 73, - 76, - 79, - 83, - 86, - 89, - 93, - 96, - 99, - 103, - 106, - 109, - 113, - 116, - 119, - 123, - 126, - 129, - 132, - 136, - 139, - 142, - 146, - 149, - 152, - 156, - 159, - 162, - 166, - 169, - 172, - 176, - 179, - 182, - 186, - 189, - 192, - 196, - 199, - 202, - 206, - 209, - 212, - 216, - 219, - 222, - 226, - 229, - 232, - 235, - 239, - 242, - 245, - 249, - 252, - 255, - 259, - 262, - 265, - 269, - 272, - 275, - 279, - 282, - 285, - 289, - 292, - 295, - 299, - 302, - 305, - 309, - 312, - 315, - 319, - 322, - 325, - 328, - 332, - 335, - 338, - 342, - 345, - 348, - 352, - 355, - 358, - 362, - 365, - 368, - 372, - 375, - 378, - 382, - 385, - 388, - 392, - 395, - 398, - 402, - 405, - 408, - 412, - 415, - 418, - 422, - 425, - 428, - 431, - 435, - 438, - 441, - 445, - 448, - 451, - 455, - 458, - 461, - 465, - 468, - 471, - 475, - 478, - 481, - 485, - 488, - 491, - 495, - 498, - 501, - 505, - 508, - 511, - 515, - 518, - 521, - 524, - 528, - 531, - 534, - 538, - 541, - 544, - 548, - 551, - 554, - 558, - 561, - 564, - 568, - 571, - 574, - 578, - 581, - 584, - 588, - 591, - 594, - 598, - 601, - 604, - 608, - 611, - 614, - 617, - 621, - 624, - 627, - 631, - 634, - 637, - 641, - 644, - 647, - 651, - 654, - 657, - 661, - 664, - 667, - 671, - 674, - 677, - 681, - 684, - 687, - 691, - 694, - 697, - 701, - 704, - 707, - 711, - 714, - 717, - 720, - 724, - 727, - 730, - 734, - 737, - 740, - 744, - 747, - 750, - 754, - 757, - 760, - 764, - 767, - 770, - 774, - 777, - 780, - 784, - 787, - 790, - 794, - 797, - 800, - 804, - 807, - 810, - 813, - 817, - 820, - 823, - 827, - 830, - 833, - 837, - 840, - 843, - 847, - 850, - 853, - 857, - 860, - 863, - 867, - 870, - 873, - 877, - 880, - 883, - 887, - 890, - 893, - 897, - 900, - 903, - 907, - 910, - 913, - 916, - 920, - 923, - 926, - 930, - 933, - 936, - 940, - 943, - 946, - 950, - ], -); - -#[rustfmt::skip] -pub const F32_SHORT_POWERS: [f32; 11] = [ - 1e0, - 1e1, - 1e2, - 1e3, - 1e4, - 1e5, - 1e6, - 1e7, - 1e8, - 1e9, - 1e10, -]; - -#[rustfmt::skip] -pub const F64_SHORT_POWERS: [f64; 23] = [ - 1e0, - 1e1, - 1e2, - 1e3, - 1e4, - 1e5, - 1e6, - 1e7, - 1e8, - 1e9, - 1e10, - 1e11, - 1e12, - 1e13, - 1e14, - 1e15, - 1e16, - 1e17, - 1e18, - 1e19, - 1e20, - 1e21, - 1e22, +pub static POWER_OF_FIVE_128: [(u64, u64); N_POWERS_OF_FIVE] = [ + (0xeef453d6923bd65a, 0x113faa2906a13b3f), // 5^-342 + (0x9558b4661b6565f8, 0x4ac7ca59a424c507), // 5^-341 + (0xbaaee17fa23ebf76, 0x5d79bcf00d2df649), // 5^-340 + (0xe95a99df8ace6f53, 0xf4d82c2c107973dc), // 5^-339 + (0x91d8a02bb6c10594, 0x79071b9b8a4be869), // 5^-338 + (0xb64ec836a47146f9, 0x9748e2826cdee284), // 5^-337 + (0xe3e27a444d8d98b7, 0xfd1b1b2308169b25), // 5^-336 + (0x8e6d8c6ab0787f72, 0xfe30f0f5e50e20f7), // 5^-335 + (0xb208ef855c969f4f, 0xbdbd2d335e51a935), // 5^-334 + (0xde8b2b66b3bc4723, 0xad2c788035e61382), // 5^-333 + (0x8b16fb203055ac76, 0x4c3bcb5021afcc31), // 5^-332 + (0xaddcb9e83c6b1793, 0xdf4abe242a1bbf3d), // 5^-331 + (0xd953e8624b85dd78, 0xd71d6dad34a2af0d), // 5^-330 + (0x87d4713d6f33aa6b, 0x8672648c40e5ad68), // 5^-329 + (0xa9c98d8ccb009506, 0x680efdaf511f18c2), // 5^-328 + (0xd43bf0effdc0ba48, 0x212bd1b2566def2), // 5^-327 + (0x84a57695fe98746d, 0x14bb630f7604b57), // 5^-326 + (0xa5ced43b7e3e9188, 0x419ea3bd35385e2d), // 5^-325 + (0xcf42894a5dce35ea, 0x52064cac828675b9), // 5^-324 + (0x818995ce7aa0e1b2, 0x7343efebd1940993), // 5^-323 + (0xa1ebfb4219491a1f, 0x1014ebe6c5f90bf8), // 5^-322 + (0xca66fa129f9b60a6, 0xd41a26e077774ef6), // 5^-321 + (0xfd00b897478238d0, 0x8920b098955522b4), // 5^-320 + (0x9e20735e8cb16382, 0x55b46e5f5d5535b0), // 5^-319 + (0xc5a890362fddbc62, 0xeb2189f734aa831d), // 5^-318 + (0xf712b443bbd52b7b, 0xa5e9ec7501d523e4), // 5^-317 + (0x9a6bb0aa55653b2d, 0x47b233c92125366e), // 5^-316 + (0xc1069cd4eabe89f8, 0x999ec0bb696e840a), // 5^-315 + (0xf148440a256e2c76, 0xc00670ea43ca250d), // 5^-314 + (0x96cd2a865764dbca, 0x380406926a5e5728), // 5^-313 + (0xbc807527ed3e12bc, 0xc605083704f5ecf2), // 5^-312 + (0xeba09271e88d976b, 0xf7864a44c633682e), // 5^-311 + (0x93445b8731587ea3, 0x7ab3ee6afbe0211d), // 5^-310 + (0xb8157268fdae9e4c, 0x5960ea05bad82964), // 5^-309 + (0xe61acf033d1a45df, 0x6fb92487298e33bd), // 5^-308 + (0x8fd0c16206306bab, 0xa5d3b6d479f8e056), // 5^-307 + (0xb3c4f1ba87bc8696, 0x8f48a4899877186c), // 5^-306 + (0xe0b62e2929aba83c, 0x331acdabfe94de87), // 5^-305 + (0x8c71dcd9ba0b4925, 0x9ff0c08b7f1d0b14), // 5^-304 + (0xaf8e5410288e1b6f, 0x7ecf0ae5ee44dd9), // 5^-303 + (0xdb71e91432b1a24a, 0xc9e82cd9f69d6150), // 5^-302 + (0x892731ac9faf056e, 0xbe311c083a225cd2), // 5^-301 + (0xab70fe17c79ac6ca, 0x6dbd630a48aaf406), // 5^-300 + (0xd64d3d9db981787d, 0x92cbbccdad5b108), // 5^-299 + (0x85f0468293f0eb4e, 0x25bbf56008c58ea5), // 5^-298 + (0xa76c582338ed2621, 0xaf2af2b80af6f24e), // 5^-297 + (0xd1476e2c07286faa, 0x1af5af660db4aee1), // 5^-296 + (0x82cca4db847945ca, 0x50d98d9fc890ed4d), // 5^-295 + (0xa37fce126597973c, 0xe50ff107bab528a0), // 5^-294 + (0xcc5fc196fefd7d0c, 0x1e53ed49a96272c8), // 5^-293 + (0xff77b1fcbebcdc4f, 0x25e8e89c13bb0f7a), // 5^-292 + (0x9faacf3df73609b1, 0x77b191618c54e9ac), // 5^-291 + (0xc795830d75038c1d, 0xd59df5b9ef6a2417), // 5^-290 + (0xf97ae3d0d2446f25, 0x4b0573286b44ad1d), // 5^-289 + (0x9becce62836ac577, 0x4ee367f9430aec32), // 5^-288 + (0xc2e801fb244576d5, 0x229c41f793cda73f), // 5^-287 + (0xf3a20279ed56d48a, 0x6b43527578c1110f), // 5^-286 + (0x9845418c345644d6, 0x830a13896b78aaa9), // 5^-285 + (0xbe5691ef416bd60c, 0x23cc986bc656d553), // 5^-284 + (0xedec366b11c6cb8f, 0x2cbfbe86b7ec8aa8), // 5^-283 + (0x94b3a202eb1c3f39, 0x7bf7d71432f3d6a9), // 5^-282 + (0xb9e08a83a5e34f07, 0xdaf5ccd93fb0cc53), // 5^-281 + (0xe858ad248f5c22c9, 0xd1b3400f8f9cff68), // 5^-280 + (0x91376c36d99995be, 0x23100809b9c21fa1), // 5^-279 + (0xb58547448ffffb2d, 0xabd40a0c2832a78a), // 5^-278 + (0xe2e69915b3fff9f9, 0x16c90c8f323f516c), // 5^-277 + (0x8dd01fad907ffc3b, 0xae3da7d97f6792e3), // 5^-276 + (0xb1442798f49ffb4a, 0x99cd11cfdf41779c), // 5^-275 + (0xdd95317f31c7fa1d, 0x40405643d711d583), // 5^-274 + (0x8a7d3eef7f1cfc52, 0x482835ea666b2572), // 5^-273 + (0xad1c8eab5ee43b66, 0xda3243650005eecf), // 5^-272 + (0xd863b256369d4a40, 0x90bed43e40076a82), // 5^-271 + (0x873e4f75e2224e68, 0x5a7744a6e804a291), // 5^-270 + (0xa90de3535aaae202, 0x711515d0a205cb36), // 5^-269 + (0xd3515c2831559a83, 0xd5a5b44ca873e03), // 5^-268 + (0x8412d9991ed58091, 0xe858790afe9486c2), // 5^-267 + (0xa5178fff668ae0b6, 0x626e974dbe39a872), // 5^-266 + (0xce5d73ff402d98e3, 0xfb0a3d212dc8128f), // 5^-265 + (0x80fa687f881c7f8e, 0x7ce66634bc9d0b99), // 5^-264 + (0xa139029f6a239f72, 0x1c1fffc1ebc44e80), // 5^-263 + (0xc987434744ac874e, 0xa327ffb266b56220), // 5^-262 + (0xfbe9141915d7a922, 0x4bf1ff9f0062baa8), // 5^-261 + (0x9d71ac8fada6c9b5, 0x6f773fc3603db4a9), // 5^-260 + (0xc4ce17b399107c22, 0xcb550fb4384d21d3), // 5^-259 + (0xf6019da07f549b2b, 0x7e2a53a146606a48), // 5^-258 + (0x99c102844f94e0fb, 0x2eda7444cbfc426d), // 5^-257 + (0xc0314325637a1939, 0xfa911155fefb5308), // 5^-256 + (0xf03d93eebc589f88, 0x793555ab7eba27ca), // 5^-255 + (0x96267c7535b763b5, 0x4bc1558b2f3458de), // 5^-254 + (0xbbb01b9283253ca2, 0x9eb1aaedfb016f16), // 5^-253 + (0xea9c227723ee8bcb, 0x465e15a979c1cadc), // 5^-252 + (0x92a1958a7675175f, 0xbfacd89ec191ec9), // 5^-251 + (0xb749faed14125d36, 0xcef980ec671f667b), // 5^-250 + (0xe51c79a85916f484, 0x82b7e12780e7401a), // 5^-249 + (0x8f31cc0937ae58d2, 0xd1b2ecb8b0908810), // 5^-248 + (0xb2fe3f0b8599ef07, 0x861fa7e6dcb4aa15), // 5^-247 + (0xdfbdcece67006ac9, 0x67a791e093e1d49a), // 5^-246 + (0x8bd6a141006042bd, 0xe0c8bb2c5c6d24e0), // 5^-245 + (0xaecc49914078536d, 0x58fae9f773886e18), // 5^-244 + (0xda7f5bf590966848, 0xaf39a475506a899e), // 5^-243 + (0x888f99797a5e012d, 0x6d8406c952429603), // 5^-242 + (0xaab37fd7d8f58178, 0xc8e5087ba6d33b83), // 5^-241 + (0xd5605fcdcf32e1d6, 0xfb1e4a9a90880a64), // 5^-240 + (0x855c3be0a17fcd26, 0x5cf2eea09a55067f), // 5^-239 + (0xa6b34ad8c9dfc06f, 0xf42faa48c0ea481e), // 5^-238 + (0xd0601d8efc57b08b, 0xf13b94daf124da26), // 5^-237 + (0x823c12795db6ce57, 0x76c53d08d6b70858), // 5^-236 + (0xa2cb1717b52481ed, 0x54768c4b0c64ca6e), // 5^-235 + (0xcb7ddcdda26da268, 0xa9942f5dcf7dfd09), // 5^-234 + (0xfe5d54150b090b02, 0xd3f93b35435d7c4c), // 5^-233 + (0x9efa548d26e5a6e1, 0xc47bc5014a1a6daf), // 5^-232 + (0xc6b8e9b0709f109a, 0x359ab6419ca1091b), // 5^-231 + (0xf867241c8cc6d4c0, 0xc30163d203c94b62), // 5^-230 + (0x9b407691d7fc44f8, 0x79e0de63425dcf1d), // 5^-229 + (0xc21094364dfb5636, 0x985915fc12f542e4), // 5^-228 + (0xf294b943e17a2bc4, 0x3e6f5b7b17b2939d), // 5^-227 + (0x979cf3ca6cec5b5a, 0xa705992ceecf9c42), // 5^-226 + (0xbd8430bd08277231, 0x50c6ff782a838353), // 5^-225 + (0xece53cec4a314ebd, 0xa4f8bf5635246428), // 5^-224 + (0x940f4613ae5ed136, 0x871b7795e136be99), // 5^-223 + (0xb913179899f68584, 0x28e2557b59846e3f), // 5^-222 + (0xe757dd7ec07426e5, 0x331aeada2fe589cf), // 5^-221 + (0x9096ea6f3848984f, 0x3ff0d2c85def7621), // 5^-220 + (0xb4bca50b065abe63, 0xfed077a756b53a9), // 5^-219 + (0xe1ebce4dc7f16dfb, 0xd3e8495912c62894), // 5^-218 + (0x8d3360f09cf6e4bd, 0x64712dd7abbbd95c), // 5^-217 + (0xb080392cc4349dec, 0xbd8d794d96aacfb3), // 5^-216 + (0xdca04777f541c567, 0xecf0d7a0fc5583a0), // 5^-215 + (0x89e42caaf9491b60, 0xf41686c49db57244), // 5^-214 + (0xac5d37d5b79b6239, 0x311c2875c522ced5), // 5^-213 + (0xd77485cb25823ac7, 0x7d633293366b828b), // 5^-212 + (0x86a8d39ef77164bc, 0xae5dff9c02033197), // 5^-211 + (0xa8530886b54dbdeb, 0xd9f57f830283fdfc), // 5^-210 + (0xd267caa862a12d66, 0xd072df63c324fd7b), // 5^-209 + (0x8380dea93da4bc60, 0x4247cb9e59f71e6d), // 5^-208 + (0xa46116538d0deb78, 0x52d9be85f074e608), // 5^-207 + (0xcd795be870516656, 0x67902e276c921f8b), // 5^-206 + (0x806bd9714632dff6, 0xba1cd8a3db53b6), // 5^-205 + (0xa086cfcd97bf97f3, 0x80e8a40eccd228a4), // 5^-204 + (0xc8a883c0fdaf7df0, 0x6122cd128006b2cd), // 5^-203 + (0xfad2a4b13d1b5d6c, 0x796b805720085f81), // 5^-202 + (0x9cc3a6eec6311a63, 0xcbe3303674053bb0), // 5^-201 + (0xc3f490aa77bd60fc, 0xbedbfc4411068a9c), // 5^-200 + (0xf4f1b4d515acb93b, 0xee92fb5515482d44), // 5^-199 + (0x991711052d8bf3c5, 0x751bdd152d4d1c4a), // 5^-198 + (0xbf5cd54678eef0b6, 0xd262d45a78a0635d), // 5^-197 + (0xef340a98172aace4, 0x86fb897116c87c34), // 5^-196 + (0x9580869f0e7aac0e, 0xd45d35e6ae3d4da0), // 5^-195 + (0xbae0a846d2195712, 0x8974836059cca109), // 5^-194 + (0xe998d258869facd7, 0x2bd1a438703fc94b), // 5^-193 + (0x91ff83775423cc06, 0x7b6306a34627ddcf), // 5^-192 + (0xb67f6455292cbf08, 0x1a3bc84c17b1d542), // 5^-191 + (0xe41f3d6a7377eeca, 0x20caba5f1d9e4a93), // 5^-190 + (0x8e938662882af53e, 0x547eb47b7282ee9c), // 5^-189 + (0xb23867fb2a35b28d, 0xe99e619a4f23aa43), // 5^-188 + (0xdec681f9f4c31f31, 0x6405fa00e2ec94d4), // 5^-187 + (0x8b3c113c38f9f37e, 0xde83bc408dd3dd04), // 5^-186 + (0xae0b158b4738705e, 0x9624ab50b148d445), // 5^-185 + (0xd98ddaee19068c76, 0x3badd624dd9b0957), // 5^-184 + (0x87f8a8d4cfa417c9, 0xe54ca5d70a80e5d6), // 5^-183 + (0xa9f6d30a038d1dbc, 0x5e9fcf4ccd211f4c), // 5^-182 + (0xd47487cc8470652b, 0x7647c3200069671f), // 5^-181 + (0x84c8d4dfd2c63f3b, 0x29ecd9f40041e073), // 5^-180 + (0xa5fb0a17c777cf09, 0xf468107100525890), // 5^-179 + (0xcf79cc9db955c2cc, 0x7182148d4066eeb4), // 5^-178 + (0x81ac1fe293d599bf, 0xc6f14cd848405530), // 5^-177 + (0xa21727db38cb002f, 0xb8ada00e5a506a7c), // 5^-176 + (0xca9cf1d206fdc03b, 0xa6d90811f0e4851c), // 5^-175 + (0xfd442e4688bd304a, 0x908f4a166d1da663), // 5^-174 + (0x9e4a9cec15763e2e, 0x9a598e4e043287fe), // 5^-173 + (0xc5dd44271ad3cdba, 0x40eff1e1853f29fd), // 5^-172 + (0xf7549530e188c128, 0xd12bee59e68ef47c), // 5^-171 + (0x9a94dd3e8cf578b9, 0x82bb74f8301958ce), // 5^-170 + (0xc13a148e3032d6e7, 0xe36a52363c1faf01), // 5^-169 + (0xf18899b1bc3f8ca1, 0xdc44e6c3cb279ac1), // 5^-168 + (0x96f5600f15a7b7e5, 0x29ab103a5ef8c0b9), // 5^-167 + (0xbcb2b812db11a5de, 0x7415d448f6b6f0e7), // 5^-166 + (0xebdf661791d60f56, 0x111b495b3464ad21), // 5^-165 + (0x936b9fcebb25c995, 0xcab10dd900beec34), // 5^-164 + (0xb84687c269ef3bfb, 0x3d5d514f40eea742), // 5^-163 + (0xe65829b3046b0afa, 0xcb4a5a3112a5112), // 5^-162 + (0x8ff71a0fe2c2e6dc, 0x47f0e785eaba72ab), // 5^-161 + (0xb3f4e093db73a093, 0x59ed216765690f56), // 5^-160 + (0xe0f218b8d25088b8, 0x306869c13ec3532c), // 5^-159 + (0x8c974f7383725573, 0x1e414218c73a13fb), // 5^-158 + (0xafbd2350644eeacf, 0xe5d1929ef90898fa), // 5^-157 + (0xdbac6c247d62a583, 0xdf45f746b74abf39), // 5^-156 + (0x894bc396ce5da772, 0x6b8bba8c328eb783), // 5^-155 + (0xab9eb47c81f5114f, 0x66ea92f3f326564), // 5^-154 + (0xd686619ba27255a2, 0xc80a537b0efefebd), // 5^-153 + (0x8613fd0145877585, 0xbd06742ce95f5f36), // 5^-152 + (0xa798fc4196e952e7, 0x2c48113823b73704), // 5^-151 + (0xd17f3b51fca3a7a0, 0xf75a15862ca504c5), // 5^-150 + (0x82ef85133de648c4, 0x9a984d73dbe722fb), // 5^-149 + (0xa3ab66580d5fdaf5, 0xc13e60d0d2e0ebba), // 5^-148 + (0xcc963fee10b7d1b3, 0x318df905079926a8), // 5^-147 + (0xffbbcfe994e5c61f, 0xfdf17746497f7052), // 5^-146 + (0x9fd561f1fd0f9bd3, 0xfeb6ea8bedefa633), // 5^-145 + (0xc7caba6e7c5382c8, 0xfe64a52ee96b8fc0), // 5^-144 + (0xf9bd690a1b68637b, 0x3dfdce7aa3c673b0), // 5^-143 + (0x9c1661a651213e2d, 0x6bea10ca65c084e), // 5^-142 + (0xc31bfa0fe5698db8, 0x486e494fcff30a62), // 5^-141 + (0xf3e2f893dec3f126, 0x5a89dba3c3efccfa), // 5^-140 + (0x986ddb5c6b3a76b7, 0xf89629465a75e01c), // 5^-139 + (0xbe89523386091465, 0xf6bbb397f1135823), // 5^-138 + (0xee2ba6c0678b597f, 0x746aa07ded582e2c), // 5^-137 + (0x94db483840b717ef, 0xa8c2a44eb4571cdc), // 5^-136 + (0xba121a4650e4ddeb, 0x92f34d62616ce413), // 5^-135 + (0xe896a0d7e51e1566, 0x77b020baf9c81d17), // 5^-134 + (0x915e2486ef32cd60, 0xace1474dc1d122e), // 5^-133 + (0xb5b5ada8aaff80b8, 0xd819992132456ba), // 5^-132 + (0xe3231912d5bf60e6, 0x10e1fff697ed6c69), // 5^-131 + (0x8df5efabc5979c8f, 0xca8d3ffa1ef463c1), // 5^-130 + (0xb1736b96b6fd83b3, 0xbd308ff8a6b17cb2), // 5^-129 + (0xddd0467c64bce4a0, 0xac7cb3f6d05ddbde), // 5^-128 + (0x8aa22c0dbef60ee4, 0x6bcdf07a423aa96b), // 5^-127 + (0xad4ab7112eb3929d, 0x86c16c98d2c953c6), // 5^-126 + (0xd89d64d57a607744, 0xe871c7bf077ba8b7), // 5^-125 + (0x87625f056c7c4a8b, 0x11471cd764ad4972), // 5^-124 + (0xa93af6c6c79b5d2d, 0xd598e40d3dd89bcf), // 5^-123 + (0xd389b47879823479, 0x4aff1d108d4ec2c3), // 5^-122 + (0x843610cb4bf160cb, 0xcedf722a585139ba), // 5^-121 + (0xa54394fe1eedb8fe, 0xc2974eb4ee658828), // 5^-120 + (0xce947a3da6a9273e, 0x733d226229feea32), // 5^-119 + (0x811ccc668829b887, 0x806357d5a3f525f), // 5^-118 + (0xa163ff802a3426a8, 0xca07c2dcb0cf26f7), // 5^-117 + (0xc9bcff6034c13052, 0xfc89b393dd02f0b5), // 5^-116 + (0xfc2c3f3841f17c67, 0xbbac2078d443ace2), // 5^-115 + (0x9d9ba7832936edc0, 0xd54b944b84aa4c0d), // 5^-114 + (0xc5029163f384a931, 0xa9e795e65d4df11), // 5^-113 + (0xf64335bcf065d37d, 0x4d4617b5ff4a16d5), // 5^-112 + (0x99ea0196163fa42e, 0x504bced1bf8e4e45), // 5^-111 + (0xc06481fb9bcf8d39, 0xe45ec2862f71e1d6), // 5^-110 + (0xf07da27a82c37088, 0x5d767327bb4e5a4c), // 5^-109 + (0x964e858c91ba2655, 0x3a6a07f8d510f86f), // 5^-108 + (0xbbe226efb628afea, 0x890489f70a55368b), // 5^-107 + (0xeadab0aba3b2dbe5, 0x2b45ac74ccea842e), // 5^-106 + (0x92c8ae6b464fc96f, 0x3b0b8bc90012929d), // 5^-105 + (0xb77ada0617e3bbcb, 0x9ce6ebb40173744), // 5^-104 + (0xe55990879ddcaabd, 0xcc420a6a101d0515), // 5^-103 + (0x8f57fa54c2a9eab6, 0x9fa946824a12232d), // 5^-102 + (0xb32df8e9f3546564, 0x47939822dc96abf9), // 5^-101 + (0xdff9772470297ebd, 0x59787e2b93bc56f7), // 5^-100 + (0x8bfbea76c619ef36, 0x57eb4edb3c55b65a), // 5^-99 + (0xaefae51477a06b03, 0xede622920b6b23f1), // 5^-98 + (0xdab99e59958885c4, 0xe95fab368e45eced), // 5^-97 + (0x88b402f7fd75539b, 0x11dbcb0218ebb414), // 5^-96 + (0xaae103b5fcd2a881, 0xd652bdc29f26a119), // 5^-95 + (0xd59944a37c0752a2, 0x4be76d3346f0495f), // 5^-94 + (0x857fcae62d8493a5, 0x6f70a4400c562ddb), // 5^-93 + (0xa6dfbd9fb8e5b88e, 0xcb4ccd500f6bb952), // 5^-92 + (0xd097ad07a71f26b2, 0x7e2000a41346a7a7), // 5^-91 + (0x825ecc24c873782f, 0x8ed400668c0c28c8), // 5^-90 + (0xa2f67f2dfa90563b, 0x728900802f0f32fa), // 5^-89 + (0xcbb41ef979346bca, 0x4f2b40a03ad2ffb9), // 5^-88 + (0xfea126b7d78186bc, 0xe2f610c84987bfa8), // 5^-87 + (0x9f24b832e6b0f436, 0xdd9ca7d2df4d7c9), // 5^-86 + (0xc6ede63fa05d3143, 0x91503d1c79720dbb), // 5^-85 + (0xf8a95fcf88747d94, 0x75a44c6397ce912a), // 5^-84 + (0x9b69dbe1b548ce7c, 0xc986afbe3ee11aba), // 5^-83 + (0xc24452da229b021b, 0xfbe85badce996168), // 5^-82 + (0xf2d56790ab41c2a2, 0xfae27299423fb9c3), // 5^-81 + (0x97c560ba6b0919a5, 0xdccd879fc967d41a), // 5^-80 + (0xbdb6b8e905cb600f, 0x5400e987bbc1c920), // 5^-79 + (0xed246723473e3813, 0x290123e9aab23b68), // 5^-78 + (0x9436c0760c86e30b, 0xf9a0b6720aaf6521), // 5^-77 + (0xb94470938fa89bce, 0xf808e40e8d5b3e69), // 5^-76 + (0xe7958cb87392c2c2, 0xb60b1d1230b20e04), // 5^-75 + (0x90bd77f3483bb9b9, 0xb1c6f22b5e6f48c2), // 5^-74 + (0xb4ecd5f01a4aa828, 0x1e38aeb6360b1af3), // 5^-73 + (0xe2280b6c20dd5232, 0x25c6da63c38de1b0), // 5^-72 + (0x8d590723948a535f, 0x579c487e5a38ad0e), // 5^-71 + (0xb0af48ec79ace837, 0x2d835a9df0c6d851), // 5^-70 + (0xdcdb1b2798182244, 0xf8e431456cf88e65), // 5^-69 + (0x8a08f0f8bf0f156b, 0x1b8e9ecb641b58ff), // 5^-68 + (0xac8b2d36eed2dac5, 0xe272467e3d222f3f), // 5^-67 + (0xd7adf884aa879177, 0x5b0ed81dcc6abb0f), // 5^-66 + (0x86ccbb52ea94baea, 0x98e947129fc2b4e9), // 5^-65 + (0xa87fea27a539e9a5, 0x3f2398d747b36224), // 5^-64 + (0xd29fe4b18e88640e, 0x8eec7f0d19a03aad), // 5^-63 + (0x83a3eeeef9153e89, 0x1953cf68300424ac), // 5^-62 + (0xa48ceaaab75a8e2b, 0x5fa8c3423c052dd7), // 5^-61 + (0xcdb02555653131b6, 0x3792f412cb06794d), // 5^-60 + (0x808e17555f3ebf11, 0xe2bbd88bbee40bd0), // 5^-59 + (0xa0b19d2ab70e6ed6, 0x5b6aceaeae9d0ec4), // 5^-58 + (0xc8de047564d20a8b, 0xf245825a5a445275), // 5^-57 + (0xfb158592be068d2e, 0xeed6e2f0f0d56712), // 5^-56 + (0x9ced737bb6c4183d, 0x55464dd69685606b), // 5^-55 + (0xc428d05aa4751e4c, 0xaa97e14c3c26b886), // 5^-54 + (0xf53304714d9265df, 0xd53dd99f4b3066a8), // 5^-53 + (0x993fe2c6d07b7fab, 0xe546a8038efe4029), // 5^-52 + (0xbf8fdb78849a5f96, 0xde98520472bdd033), // 5^-51 + (0xef73d256a5c0f77c, 0x963e66858f6d4440), // 5^-50 + (0x95a8637627989aad, 0xdde7001379a44aa8), // 5^-49 + (0xbb127c53b17ec159, 0x5560c018580d5d52), // 5^-48 + (0xe9d71b689dde71af, 0xaab8f01e6e10b4a6), // 5^-47 + (0x9226712162ab070d, 0xcab3961304ca70e8), // 5^-46 + (0xb6b00d69bb55c8d1, 0x3d607b97c5fd0d22), // 5^-45 + (0xe45c10c42a2b3b05, 0x8cb89a7db77c506a), // 5^-44 + (0x8eb98a7a9a5b04e3, 0x77f3608e92adb242), // 5^-43 + (0xb267ed1940f1c61c, 0x55f038b237591ed3), // 5^-42 + (0xdf01e85f912e37a3, 0x6b6c46dec52f6688), // 5^-41 + (0x8b61313bbabce2c6, 0x2323ac4b3b3da015), // 5^-40 + (0xae397d8aa96c1b77, 0xabec975e0a0d081a), // 5^-39 + (0xd9c7dced53c72255, 0x96e7bd358c904a21), // 5^-38 + (0x881cea14545c7575, 0x7e50d64177da2e54), // 5^-37 + (0xaa242499697392d2, 0xdde50bd1d5d0b9e9), // 5^-36 + (0xd4ad2dbfc3d07787, 0x955e4ec64b44e864), // 5^-35 + (0x84ec3c97da624ab4, 0xbd5af13bef0b113e), // 5^-34 + (0xa6274bbdd0fadd61, 0xecb1ad8aeacdd58e), // 5^-33 + (0xcfb11ead453994ba, 0x67de18eda5814af2), // 5^-32 + (0x81ceb32c4b43fcf4, 0x80eacf948770ced7), // 5^-31 + (0xa2425ff75e14fc31, 0xa1258379a94d028d), // 5^-30 + (0xcad2f7f5359a3b3e, 0x96ee45813a04330), // 5^-29 + (0xfd87b5f28300ca0d, 0x8bca9d6e188853fc), // 5^-28 + (0x9e74d1b791e07e48, 0x775ea264cf55347e), // 5^-27 + (0xc612062576589dda, 0x95364afe032a819e), // 5^-26 + (0xf79687aed3eec551, 0x3a83ddbd83f52205), // 5^-25 + (0x9abe14cd44753b52, 0xc4926a9672793543), // 5^-24 + (0xc16d9a0095928a27, 0x75b7053c0f178294), // 5^-23 + (0xf1c90080baf72cb1, 0x5324c68b12dd6339), // 5^-22 + (0x971da05074da7bee, 0xd3f6fc16ebca5e04), // 5^-21 + (0xbce5086492111aea, 0x88f4bb1ca6bcf585), // 5^-20 + (0xec1e4a7db69561a5, 0x2b31e9e3d06c32e6), // 5^-19 + (0x9392ee8e921d5d07, 0x3aff322e62439fd0), // 5^-18 + (0xb877aa3236a4b449, 0x9befeb9fad487c3), // 5^-17 + (0xe69594bec44de15b, 0x4c2ebe687989a9b4), // 5^-16 + (0x901d7cf73ab0acd9, 0xf9d37014bf60a11), // 5^-15 + (0xb424dc35095cd80f, 0x538484c19ef38c95), // 5^-14 + (0xe12e13424bb40e13, 0x2865a5f206b06fba), // 5^-13 + (0x8cbccc096f5088cb, 0xf93f87b7442e45d4), // 5^-12 + (0xafebff0bcb24aafe, 0xf78f69a51539d749), // 5^-11 + (0xdbe6fecebdedd5be, 0xb573440e5a884d1c), // 5^-10 + (0x89705f4136b4a597, 0x31680a88f8953031), // 5^-9 + (0xabcc77118461cefc, 0xfdc20d2b36ba7c3e), // 5^-8 + (0xd6bf94d5e57a42bc, 0x3d32907604691b4d), // 5^-7 + (0x8637bd05af6c69b5, 0xa63f9a49c2c1b110), // 5^-6 + (0xa7c5ac471b478423, 0xfcf80dc33721d54), // 5^-5 + (0xd1b71758e219652b, 0xd3c36113404ea4a9), // 5^-4 + (0x83126e978d4fdf3b, 0x645a1cac083126ea), // 5^-3 + (0xa3d70a3d70a3d70a, 0x3d70a3d70a3d70a4), // 5^-2 + (0xcccccccccccccccc, 0xcccccccccccccccd), // 5^-1 + (0x8000000000000000, 0x0), // 5^0 + (0xa000000000000000, 0x0), // 5^1 + (0xc800000000000000, 0x0), // 5^2 + (0xfa00000000000000, 0x0), // 5^3 + (0x9c40000000000000, 0x0), // 5^4 + (0xc350000000000000, 0x0), // 5^5 + (0xf424000000000000, 0x0), // 5^6 + (0x9896800000000000, 0x0), // 5^7 + (0xbebc200000000000, 0x0), // 5^8 + (0xee6b280000000000, 0x0), // 5^9 + (0x9502f90000000000, 0x0), // 5^10 + (0xba43b74000000000, 0x0), // 5^11 + (0xe8d4a51000000000, 0x0), // 5^12 + (0x9184e72a00000000, 0x0), // 5^13 + (0xb5e620f480000000, 0x0), // 5^14 + (0xe35fa931a0000000, 0x0), // 5^15 + (0x8e1bc9bf04000000, 0x0), // 5^16 + (0xb1a2bc2ec5000000, 0x0), // 5^17 + (0xde0b6b3a76400000, 0x0), // 5^18 + (0x8ac7230489e80000, 0x0), // 5^19 + (0xad78ebc5ac620000, 0x0), // 5^20 + (0xd8d726b7177a8000, 0x0), // 5^21 + (0x878678326eac9000, 0x0), // 5^22 + (0xa968163f0a57b400, 0x0), // 5^23 + (0xd3c21bcecceda100, 0x0), // 5^24 + (0x84595161401484a0, 0x0), // 5^25 + (0xa56fa5b99019a5c8, 0x0), // 5^26 + (0xcecb8f27f4200f3a, 0x0), // 5^27 + (0x813f3978f8940984, 0x4000000000000000), // 5^28 + (0xa18f07d736b90be5, 0x5000000000000000), // 5^29 + (0xc9f2c9cd04674ede, 0xa400000000000000), // 5^30 + (0xfc6f7c4045812296, 0x4d00000000000000), // 5^31 + (0x9dc5ada82b70b59d, 0xf020000000000000), // 5^32 + (0xc5371912364ce305, 0x6c28000000000000), // 5^33 + (0xf684df56c3e01bc6, 0xc732000000000000), // 5^34 + (0x9a130b963a6c115c, 0x3c7f400000000000), // 5^35 + (0xc097ce7bc90715b3, 0x4b9f100000000000), // 5^36 + (0xf0bdc21abb48db20, 0x1e86d40000000000), // 5^37 + (0x96769950b50d88f4, 0x1314448000000000), // 5^38 + (0xbc143fa4e250eb31, 0x17d955a000000000), // 5^39 + (0xeb194f8e1ae525fd, 0x5dcfab0800000000), // 5^40 + (0x92efd1b8d0cf37be, 0x5aa1cae500000000), // 5^41 + (0xb7abc627050305ad, 0xf14a3d9e40000000), // 5^42 + (0xe596b7b0c643c719, 0x6d9ccd05d0000000), // 5^43 + (0x8f7e32ce7bea5c6f, 0xe4820023a2000000), // 5^44 + (0xb35dbf821ae4f38b, 0xdda2802c8a800000), // 5^45 + (0xe0352f62a19e306e, 0xd50b2037ad200000), // 5^46 + (0x8c213d9da502de45, 0x4526f422cc340000), // 5^47 + (0xaf298d050e4395d6, 0x9670b12b7f410000), // 5^48 + (0xdaf3f04651d47b4c, 0x3c0cdd765f114000), // 5^49 + (0x88d8762bf324cd0f, 0xa5880a69fb6ac800), // 5^50 + (0xab0e93b6efee0053, 0x8eea0d047a457a00), // 5^51 + (0xd5d238a4abe98068, 0x72a4904598d6d880), // 5^52 + (0x85a36366eb71f041, 0x47a6da2b7f864750), // 5^53 + (0xa70c3c40a64e6c51, 0x999090b65f67d924), // 5^54 + (0xd0cf4b50cfe20765, 0xfff4b4e3f741cf6d), // 5^55 + (0x82818f1281ed449f, 0xbff8f10e7a8921a4), // 5^56 + (0xa321f2d7226895c7, 0xaff72d52192b6a0d), // 5^57 + (0xcbea6f8ceb02bb39, 0x9bf4f8a69f764490), // 5^58 + (0xfee50b7025c36a08, 0x2f236d04753d5b4), // 5^59 + (0x9f4f2726179a2245, 0x1d762422c946590), // 5^60 + (0xc722f0ef9d80aad6, 0x424d3ad2b7b97ef5), // 5^61 + (0xf8ebad2b84e0d58b, 0xd2e0898765a7deb2), // 5^62 + (0x9b934c3b330c8577, 0x63cc55f49f88eb2f), // 5^63 + (0xc2781f49ffcfa6d5, 0x3cbf6b71c76b25fb), // 5^64 + (0xf316271c7fc3908a, 0x8bef464e3945ef7a), // 5^65 + (0x97edd871cfda3a56, 0x97758bf0e3cbb5ac), // 5^66 + (0xbde94e8e43d0c8ec, 0x3d52eeed1cbea317), // 5^67 + (0xed63a231d4c4fb27, 0x4ca7aaa863ee4bdd), // 5^68 + (0x945e455f24fb1cf8, 0x8fe8caa93e74ef6a), // 5^69 + (0xb975d6b6ee39e436, 0xb3e2fd538e122b44), // 5^70 + (0xe7d34c64a9c85d44, 0x60dbbca87196b616), // 5^71 + (0x90e40fbeea1d3a4a, 0xbc8955e946fe31cd), // 5^72 + (0xb51d13aea4a488dd, 0x6babab6398bdbe41), // 5^73 + (0xe264589a4dcdab14, 0xc696963c7eed2dd1), // 5^74 + (0x8d7eb76070a08aec, 0xfc1e1de5cf543ca2), // 5^75 + (0xb0de65388cc8ada8, 0x3b25a55f43294bcb), // 5^76 + (0xdd15fe86affad912, 0x49ef0eb713f39ebe), // 5^77 + (0x8a2dbf142dfcc7ab, 0x6e3569326c784337), // 5^78 + (0xacb92ed9397bf996, 0x49c2c37f07965404), // 5^79 + (0xd7e77a8f87daf7fb, 0xdc33745ec97be906), // 5^80 + (0x86f0ac99b4e8dafd, 0x69a028bb3ded71a3), // 5^81 + (0xa8acd7c0222311bc, 0xc40832ea0d68ce0c), // 5^82 + (0xd2d80db02aabd62b, 0xf50a3fa490c30190), // 5^83 + (0x83c7088e1aab65db, 0x792667c6da79e0fa), // 5^84 + (0xa4b8cab1a1563f52, 0x577001b891185938), // 5^85 + (0xcde6fd5e09abcf26, 0xed4c0226b55e6f86), // 5^86 + (0x80b05e5ac60b6178, 0x544f8158315b05b4), // 5^87 + (0xa0dc75f1778e39d6, 0x696361ae3db1c721), // 5^88 + (0xc913936dd571c84c, 0x3bc3a19cd1e38e9), // 5^89 + (0xfb5878494ace3a5f, 0x4ab48a04065c723), // 5^90 + (0x9d174b2dcec0e47b, 0x62eb0d64283f9c76), // 5^91 + (0xc45d1df942711d9a, 0x3ba5d0bd324f8394), // 5^92 + (0xf5746577930d6500, 0xca8f44ec7ee36479), // 5^93 + (0x9968bf6abbe85f20, 0x7e998b13cf4e1ecb), // 5^94 + (0xbfc2ef456ae276e8, 0x9e3fedd8c321a67e), // 5^95 + (0xefb3ab16c59b14a2, 0xc5cfe94ef3ea101e), // 5^96 + (0x95d04aee3b80ece5, 0xbba1f1d158724a12), // 5^97 + (0xbb445da9ca61281f, 0x2a8a6e45ae8edc97), // 5^98 + (0xea1575143cf97226, 0xf52d09d71a3293bd), // 5^99 + (0x924d692ca61be758, 0x593c2626705f9c56), // 5^100 + (0xb6e0c377cfa2e12e, 0x6f8b2fb00c77836c), // 5^101 + (0xe498f455c38b997a, 0xb6dfb9c0f956447), // 5^102 + (0x8edf98b59a373fec, 0x4724bd4189bd5eac), // 5^103 + (0xb2977ee300c50fe7, 0x58edec91ec2cb657), // 5^104 + (0xdf3d5e9bc0f653e1, 0x2f2967b66737e3ed), // 5^105 + (0x8b865b215899f46c, 0xbd79e0d20082ee74), // 5^106 + (0xae67f1e9aec07187, 0xecd8590680a3aa11), // 5^107 + (0xda01ee641a708de9, 0xe80e6f4820cc9495), // 5^108 + (0x884134fe908658b2, 0x3109058d147fdcdd), // 5^109 + (0xaa51823e34a7eede, 0xbd4b46f0599fd415), // 5^110 + (0xd4e5e2cdc1d1ea96, 0x6c9e18ac7007c91a), // 5^111 + (0x850fadc09923329e, 0x3e2cf6bc604ddb0), // 5^112 + (0xa6539930bf6bff45, 0x84db8346b786151c), // 5^113 + (0xcfe87f7cef46ff16, 0xe612641865679a63), // 5^114 + (0x81f14fae158c5f6e, 0x4fcb7e8f3f60c07e), // 5^115 + (0xa26da3999aef7749, 0xe3be5e330f38f09d), // 5^116 + (0xcb090c8001ab551c, 0x5cadf5bfd3072cc5), // 5^117 + (0xfdcb4fa002162a63, 0x73d9732fc7c8f7f6), // 5^118 + (0x9e9f11c4014dda7e, 0x2867e7fddcdd9afa), // 5^119 + (0xc646d63501a1511d, 0xb281e1fd541501b8), // 5^120 + (0xf7d88bc24209a565, 0x1f225a7ca91a4226), // 5^121 + (0x9ae757596946075f, 0x3375788de9b06958), // 5^122 + (0xc1a12d2fc3978937, 0x52d6b1641c83ae), // 5^123 + (0xf209787bb47d6b84, 0xc0678c5dbd23a49a), // 5^124 + (0x9745eb4d50ce6332, 0xf840b7ba963646e0), // 5^125 + (0xbd176620a501fbff, 0xb650e5a93bc3d898), // 5^126 + (0xec5d3fa8ce427aff, 0xa3e51f138ab4cebe), // 5^127 + (0x93ba47c980e98cdf, 0xc66f336c36b10137), // 5^128 + (0xb8a8d9bbe123f017, 0xb80b0047445d4184), // 5^129 + (0xe6d3102ad96cec1d, 0xa60dc059157491e5), // 5^130 + (0x9043ea1ac7e41392, 0x87c89837ad68db2f), // 5^131 + (0xb454e4a179dd1877, 0x29babe4598c311fb), // 5^132 + (0xe16a1dc9d8545e94, 0xf4296dd6fef3d67a), // 5^133 + (0x8ce2529e2734bb1d, 0x1899e4a65f58660c), // 5^134 + (0xb01ae745b101e9e4, 0x5ec05dcff72e7f8f), // 5^135 + (0xdc21a1171d42645d, 0x76707543f4fa1f73), // 5^136 + (0x899504ae72497eba, 0x6a06494a791c53a8), // 5^137 + (0xabfa45da0edbde69, 0x487db9d17636892), // 5^138 + (0xd6f8d7509292d603, 0x45a9d2845d3c42b6), // 5^139 + (0x865b86925b9bc5c2, 0xb8a2392ba45a9b2), // 5^140 + (0xa7f26836f282b732, 0x8e6cac7768d7141e), // 5^141 + (0xd1ef0244af2364ff, 0x3207d795430cd926), // 5^142 + (0x8335616aed761f1f, 0x7f44e6bd49e807b8), // 5^143 + (0xa402b9c5a8d3a6e7, 0x5f16206c9c6209a6), // 5^144 + (0xcd036837130890a1, 0x36dba887c37a8c0f), // 5^145 + (0x802221226be55a64, 0xc2494954da2c9789), // 5^146 + (0xa02aa96b06deb0fd, 0xf2db9baa10b7bd6c), // 5^147 + (0xc83553c5c8965d3d, 0x6f92829494e5acc7), // 5^148 + (0xfa42a8b73abbf48c, 0xcb772339ba1f17f9), // 5^149 + (0x9c69a97284b578d7, 0xff2a760414536efb), // 5^150 + (0xc38413cf25e2d70d, 0xfef5138519684aba), // 5^151 + (0xf46518c2ef5b8cd1, 0x7eb258665fc25d69), // 5^152 + (0x98bf2f79d5993802, 0xef2f773ffbd97a61), // 5^153 + (0xbeeefb584aff8603, 0xaafb550ffacfd8fa), // 5^154 + (0xeeaaba2e5dbf6784, 0x95ba2a53f983cf38), // 5^155 + (0x952ab45cfa97a0b2, 0xdd945a747bf26183), // 5^156 + (0xba756174393d88df, 0x94f971119aeef9e4), // 5^157 + (0xe912b9d1478ceb17, 0x7a37cd5601aab85d), // 5^158 + (0x91abb422ccb812ee, 0xac62e055c10ab33a), // 5^159 + (0xb616a12b7fe617aa, 0x577b986b314d6009), // 5^160 + (0xe39c49765fdf9d94, 0xed5a7e85fda0b80b), // 5^161 + (0x8e41ade9fbebc27d, 0x14588f13be847307), // 5^162 + (0xb1d219647ae6b31c, 0x596eb2d8ae258fc8), // 5^163 + (0xde469fbd99a05fe3, 0x6fca5f8ed9aef3bb), // 5^164 + (0x8aec23d680043bee, 0x25de7bb9480d5854), // 5^165 + (0xada72ccc20054ae9, 0xaf561aa79a10ae6a), // 5^166 + (0xd910f7ff28069da4, 0x1b2ba1518094da04), // 5^167 + (0x87aa9aff79042286, 0x90fb44d2f05d0842), // 5^168 + (0xa99541bf57452b28, 0x353a1607ac744a53), // 5^169 + (0xd3fa922f2d1675f2, 0x42889b8997915ce8), // 5^170 + (0x847c9b5d7c2e09b7, 0x69956135febada11), // 5^171 + (0xa59bc234db398c25, 0x43fab9837e699095), // 5^172 + (0xcf02b2c21207ef2e, 0x94f967e45e03f4bb), // 5^173 + (0x8161afb94b44f57d, 0x1d1be0eebac278f5), // 5^174 + (0xa1ba1ba79e1632dc, 0x6462d92a69731732), // 5^175 + (0xca28a291859bbf93, 0x7d7b8f7503cfdcfe), // 5^176 + (0xfcb2cb35e702af78, 0x5cda735244c3d43e), // 5^177 + (0x9defbf01b061adab, 0x3a0888136afa64a7), // 5^178 + (0xc56baec21c7a1916, 0x88aaa1845b8fdd0), // 5^179 + (0xf6c69a72a3989f5b, 0x8aad549e57273d45), // 5^180 + (0x9a3c2087a63f6399, 0x36ac54e2f678864b), // 5^181 + (0xc0cb28a98fcf3c7f, 0x84576a1bb416a7dd), // 5^182 + (0xf0fdf2d3f3c30b9f, 0x656d44a2a11c51d5), // 5^183 + (0x969eb7c47859e743, 0x9f644ae5a4b1b325), // 5^184 + (0xbc4665b596706114, 0x873d5d9f0dde1fee), // 5^185 + (0xeb57ff22fc0c7959, 0xa90cb506d155a7ea), // 5^186 + (0x9316ff75dd87cbd8, 0x9a7f12442d588f2), // 5^187 + (0xb7dcbf5354e9bece, 0xc11ed6d538aeb2f), // 5^188 + (0xe5d3ef282a242e81, 0x8f1668c8a86da5fa), // 5^189 + (0x8fa475791a569d10, 0xf96e017d694487bc), // 5^190 + (0xb38d92d760ec4455, 0x37c981dcc395a9ac), // 5^191 + (0xe070f78d3927556a, 0x85bbe253f47b1417), // 5^192 + (0x8c469ab843b89562, 0x93956d7478ccec8e), // 5^193 + (0xaf58416654a6babb, 0x387ac8d1970027b2), // 5^194 + (0xdb2e51bfe9d0696a, 0x6997b05fcc0319e), // 5^195 + (0x88fcf317f22241e2, 0x441fece3bdf81f03), // 5^196 + (0xab3c2fddeeaad25a, 0xd527e81cad7626c3), // 5^197 + (0xd60b3bd56a5586f1, 0x8a71e223d8d3b074), // 5^198 + (0x85c7056562757456, 0xf6872d5667844e49), // 5^199 + (0xa738c6bebb12d16c, 0xb428f8ac016561db), // 5^200 + (0xd106f86e69d785c7, 0xe13336d701beba52), // 5^201 + (0x82a45b450226b39c, 0xecc0024661173473), // 5^202 + (0xa34d721642b06084, 0x27f002d7f95d0190), // 5^203 + (0xcc20ce9bd35c78a5, 0x31ec038df7b441f4), // 5^204 + (0xff290242c83396ce, 0x7e67047175a15271), // 5^205 + (0x9f79a169bd203e41, 0xf0062c6e984d386), // 5^206 + (0xc75809c42c684dd1, 0x52c07b78a3e60868), // 5^207 + (0xf92e0c3537826145, 0xa7709a56ccdf8a82), // 5^208 + (0x9bbcc7a142b17ccb, 0x88a66076400bb691), // 5^209 + (0xc2abf989935ddbfe, 0x6acff893d00ea435), // 5^210 + (0xf356f7ebf83552fe, 0x583f6b8c4124d43), // 5^211 + (0x98165af37b2153de, 0xc3727a337a8b704a), // 5^212 + (0xbe1bf1b059e9a8d6, 0x744f18c0592e4c5c), // 5^213 + (0xeda2ee1c7064130c, 0x1162def06f79df73), // 5^214 + (0x9485d4d1c63e8be7, 0x8addcb5645ac2ba8), // 5^215 + (0xb9a74a0637ce2ee1, 0x6d953e2bd7173692), // 5^216 + (0xe8111c87c5c1ba99, 0xc8fa8db6ccdd0437), // 5^217 + (0x910ab1d4db9914a0, 0x1d9c9892400a22a2), // 5^218 + (0xb54d5e4a127f59c8, 0x2503beb6d00cab4b), // 5^219 + (0xe2a0b5dc971f303a, 0x2e44ae64840fd61d), // 5^220 + (0x8da471a9de737e24, 0x5ceaecfed289e5d2), // 5^221 + (0xb10d8e1456105dad, 0x7425a83e872c5f47), // 5^222 + (0xdd50f1996b947518, 0xd12f124e28f77719), // 5^223 + (0x8a5296ffe33cc92f, 0x82bd6b70d99aaa6f), // 5^224 + (0xace73cbfdc0bfb7b, 0x636cc64d1001550b), // 5^225 + (0xd8210befd30efa5a, 0x3c47f7e05401aa4e), // 5^226 + (0x8714a775e3e95c78, 0x65acfaec34810a71), // 5^227 + (0xa8d9d1535ce3b396, 0x7f1839a741a14d0d), // 5^228 + (0xd31045a8341ca07c, 0x1ede48111209a050), // 5^229 + (0x83ea2b892091e44d, 0x934aed0aab460432), // 5^230 + (0xa4e4b66b68b65d60, 0xf81da84d5617853f), // 5^231 + (0xce1de40642e3f4b9, 0x36251260ab9d668e), // 5^232 + (0x80d2ae83e9ce78f3, 0xc1d72b7c6b426019), // 5^233 + (0xa1075a24e4421730, 0xb24cf65b8612f81f), // 5^234 + (0xc94930ae1d529cfc, 0xdee033f26797b627), // 5^235 + (0xfb9b7cd9a4a7443c, 0x169840ef017da3b1), // 5^236 + (0x9d412e0806e88aa5, 0x8e1f289560ee864e), // 5^237 + (0xc491798a08a2ad4e, 0xf1a6f2bab92a27e2), // 5^238 + (0xf5b5d7ec8acb58a2, 0xae10af696774b1db), // 5^239 + (0x9991a6f3d6bf1765, 0xacca6da1e0a8ef29), // 5^240 + (0xbff610b0cc6edd3f, 0x17fd090a58d32af3), // 5^241 + (0xeff394dcff8a948e, 0xddfc4b4cef07f5b0), // 5^242 + (0x95f83d0a1fb69cd9, 0x4abdaf101564f98e), // 5^243 + (0xbb764c4ca7a4440f, 0x9d6d1ad41abe37f1), // 5^244 + (0xea53df5fd18d5513, 0x84c86189216dc5ed), // 5^245 + (0x92746b9be2f8552c, 0x32fd3cf5b4e49bb4), // 5^246 + (0xb7118682dbb66a77, 0x3fbc8c33221dc2a1), // 5^247 + (0xe4d5e82392a40515, 0xfabaf3feaa5334a), // 5^248 + (0x8f05b1163ba6832d, 0x29cb4d87f2a7400e), // 5^249 + (0xb2c71d5bca9023f8, 0x743e20e9ef511012), // 5^250 + (0xdf78e4b2bd342cf6, 0x914da9246b255416), // 5^251 + (0x8bab8eefb6409c1a, 0x1ad089b6c2f7548e), // 5^252 + (0xae9672aba3d0c320, 0xa184ac2473b529b1), // 5^253 + (0xda3c0f568cc4f3e8, 0xc9e5d72d90a2741e), // 5^254 + (0x8865899617fb1871, 0x7e2fa67c7a658892), // 5^255 + (0xaa7eebfb9df9de8d, 0xddbb901b98feeab7), // 5^256 + (0xd51ea6fa85785631, 0x552a74227f3ea565), // 5^257 + (0x8533285c936b35de, 0xd53a88958f87275f), // 5^258 + (0xa67ff273b8460356, 0x8a892abaf368f137), // 5^259 + (0xd01fef10a657842c, 0x2d2b7569b0432d85), // 5^260 + (0x8213f56a67f6b29b, 0x9c3b29620e29fc73), // 5^261 + (0xa298f2c501f45f42, 0x8349f3ba91b47b8f), // 5^262 + (0xcb3f2f7642717713, 0x241c70a936219a73), // 5^263 + (0xfe0efb53d30dd4d7, 0xed238cd383aa0110), // 5^264 + (0x9ec95d1463e8a506, 0xf4363804324a40aa), // 5^265 + (0xc67bb4597ce2ce48, 0xb143c6053edcd0d5), // 5^266 + (0xf81aa16fdc1b81da, 0xdd94b7868e94050a), // 5^267 + (0x9b10a4e5e9913128, 0xca7cf2b4191c8326), // 5^268 + (0xc1d4ce1f63f57d72, 0xfd1c2f611f63a3f0), // 5^269 + (0xf24a01a73cf2dccf, 0xbc633b39673c8cec), // 5^270 + (0x976e41088617ca01, 0xd5be0503e085d813), // 5^271 + (0xbd49d14aa79dbc82, 0x4b2d8644d8a74e18), // 5^272 + (0xec9c459d51852ba2, 0xddf8e7d60ed1219e), // 5^273 + (0x93e1ab8252f33b45, 0xcabb90e5c942b503), // 5^274 + (0xb8da1662e7b00a17, 0x3d6a751f3b936243), // 5^275 + (0xe7109bfba19c0c9d, 0xcc512670a783ad4), // 5^276 + (0x906a617d450187e2, 0x27fb2b80668b24c5), // 5^277 + (0xb484f9dc9641e9da, 0xb1f9f660802dedf6), // 5^278 + (0xe1a63853bbd26451, 0x5e7873f8a0396973), // 5^279 + (0x8d07e33455637eb2, 0xdb0b487b6423e1e8), // 5^280 + (0xb049dc016abc5e5f, 0x91ce1a9a3d2cda62), // 5^281 + (0xdc5c5301c56b75f7, 0x7641a140cc7810fb), // 5^282 + (0x89b9b3e11b6329ba, 0xa9e904c87fcb0a9d), // 5^283 + (0xac2820d9623bf429, 0x546345fa9fbdcd44), // 5^284 + (0xd732290fbacaf133, 0xa97c177947ad4095), // 5^285 + (0x867f59a9d4bed6c0, 0x49ed8eabcccc485d), // 5^286 + (0xa81f301449ee8c70, 0x5c68f256bfff5a74), // 5^287 + (0xd226fc195c6a2f8c, 0x73832eec6fff3111), // 5^288 + (0x83585d8fd9c25db7, 0xc831fd53c5ff7eab), // 5^289 + (0xa42e74f3d032f525, 0xba3e7ca8b77f5e55), // 5^290 + (0xcd3a1230c43fb26f, 0x28ce1bd2e55f35eb), // 5^291 + (0x80444b5e7aa7cf85, 0x7980d163cf5b81b3), // 5^292 + (0xa0555e361951c366, 0xd7e105bcc332621f), // 5^293 + (0xc86ab5c39fa63440, 0x8dd9472bf3fefaa7), // 5^294 + (0xfa856334878fc150, 0xb14f98f6f0feb951), // 5^295 + (0x9c935e00d4b9d8d2, 0x6ed1bf9a569f33d3), // 5^296 + (0xc3b8358109e84f07, 0xa862f80ec4700c8), // 5^297 + (0xf4a642e14c6262c8, 0xcd27bb612758c0fa), // 5^298 + (0x98e7e9cccfbd7dbd, 0x8038d51cb897789c), // 5^299 + (0xbf21e44003acdd2c, 0xe0470a63e6bd56c3), // 5^300 + (0xeeea5d5004981478, 0x1858ccfce06cac74), // 5^301 + (0x95527a5202df0ccb, 0xf37801e0c43ebc8), // 5^302 + (0xbaa718e68396cffd, 0xd30560258f54e6ba), // 5^303 + (0xe950df20247c83fd, 0x47c6b82ef32a2069), // 5^304 + (0x91d28b7416cdd27e, 0x4cdc331d57fa5441), // 5^305 + (0xb6472e511c81471d, 0xe0133fe4adf8e952), // 5^306 + (0xe3d8f9e563a198e5, 0x58180fddd97723a6), // 5^307 + (0x8e679c2f5e44ff8f, 0x570f09eaa7ea7648), // 5^308 ]; diff --git a/library/core/src/num/diy_float.rs b/library/core/src/num/diy_float.rs index 0a609417dcf..ce7f6475d05 100644 --- a/library/core/src/num/diy_float.rs +++ b/library/core/src/num/diy_float.rs @@ -65,7 +65,7 @@ impl Fp { f <<= 1; e -= 1; } - debug_assert!(f >= (1 >> 63)); + debug_assert!(f >= (1 << 63)); Fp { f, e } } diff --git a/library/core/src/num/error.rs b/library/core/src/num/error.rs index e2cc8faf854..cdeba9c0792 100644 --- a/library/core/src/num/error.rs +++ b/library/core/src/num/error.rs @@ -74,26 +74,20 @@ pub struct ParseIntError { /// # Example /// /// ``` -/// #![feature(int_error_matching)] -/// /// # fn main() { /// if let Err(e) = i32::from_str_radix("a12", 10) { /// println!("Failed conversion to i32: {:?}", e.kind()); /// } /// # } /// ``` -#[unstable( - feature = "int_error_matching", - reason = "it can be useful to match errors when making error messages \ - for integer parsing", - issue = "22639" -)] +#[stable(feature = "int_error_matching", since = "1.55.0")] #[derive(Debug, Clone, PartialEq, Eq)] #[non_exhaustive] pub enum IntErrorKind { /// Value being parsed is empty. /// - /// Among other causes, this variant will be constructed when parsing an empty string. + /// This variant will be constructed when parsing an empty string. + #[stable(feature = "int_error_matching", since = "1.55.0")] Empty, /// Contains an invalid digit in its context. /// @@ -102,26 +96,25 @@ pub enum IntErrorKind { /// /// This variant is also constructed when a `+` or `-` is misplaced within a string /// either on its own or in the middle of a number. + #[stable(feature = "int_error_matching", since = "1.55.0")] InvalidDigit, /// Integer is too large to store in target integer type. + #[stable(feature = "int_error_matching", since = "1.55.0")] PosOverflow, /// Integer is too small to store in target integer type. + #[stable(feature = "int_error_matching", since = "1.55.0")] NegOverflow, /// Value was Zero /// /// This variant will be emitted when the parsing string has a value of zero, which /// would be illegal for non-zero types. + #[stable(feature = "int_error_matching", since = "1.55.0")] Zero, } impl ParseIntError { /// Outputs the detailed cause of parsing an integer failing. - #[unstable( - feature = "int_error_matching", - reason = "it can be useful to match errors when making error messages \ - for integer parsing", - issue = "22639" - )] + #[stable(feature = "int_error_matching", since = "1.55.0")] pub fn kind(&self) -> &IntErrorKind { &self.kind } diff --git a/library/core/src/num/flt2dec/decoder.rs b/library/core/src/num/flt2dec/decoder.rs index c43536c6fcc..5763860540a 100644 --- a/library/core/src/num/flt2dec/decoder.rs +++ b/library/core/src/num/flt2dec/decoder.rs @@ -1,6 +1,6 @@ //! Decodes a floating-point value into individual parts and error ranges. -use crate::num::dec2flt::rawfp::RawFloat; +use crate::num::dec2flt::float::RawFloat; use crate::num::FpCategory; /// Decoded unsigned finite value, such that: diff --git a/library/core/src/num/flt2dec/mod.rs b/library/core/src/num/flt2dec/mod.rs index 93bdf5040e0..1ff2e8c8228 100644 --- a/library/core/src/num/flt2dec/mod.rs +++ b/library/core/src/num/flt2dec/mod.rs @@ -49,7 +49,7 @@ the supplied buffer and let the algorithm to return. # Implementation overview It is easy to get the floating point printing correct but slow (Russ Cox has -[demonstrated](http://research.swtch.com/ftoa) how it's easy), or incorrect but +[demonstrated](https://research.swtch.com/ftoa) how it's easy), or incorrect but fast (naïve division and modulo). But it is surprisingly hard to print floating point numbers correctly *and* efficiently. @@ -124,6 +124,7 @@ functions. pub use self::decoder::{decode, DecodableFloat, Decoded, FullDecoded}; +use super::fmt::{Formatted, Part}; use crate::mem::MaybeUninit; pub mod decoder; @@ -170,107 +171,6 @@ pub fn round_up(d: &mut [u8]) -> Option<u8> { } } -/// Formatted parts. -#[derive(Copy, Clone, PartialEq, Eq, Debug)] -pub enum Part<'a> { - /// Given number of zero digits. - Zero(usize), - /// A literal number up to 5 digits. - Num(u16), - /// A verbatim copy of given bytes. - Copy(&'a [u8]), -} - -impl<'a> Part<'a> { - /// Returns the exact byte length of given part. - pub fn len(&self) -> usize { - match *self { - Part::Zero(nzeroes) => nzeroes, - Part::Num(v) => { - if v < 1_000 { - if v < 10 { - 1 - } else if v < 100 { - 2 - } else { - 3 - } - } else { - if v < 10_000 { 4 } else { 5 } - } - } - Part::Copy(buf) => buf.len(), - } - } - - /// Writes a part into the supplied buffer. - /// Returns the number of written bytes, or `None` if the buffer is not enough. - /// (It may still leave partially written bytes in the buffer; do not rely on that.) - pub fn write(&self, out: &mut [u8]) -> Option<usize> { - let len = self.len(); - if out.len() >= len { - match *self { - Part::Zero(nzeroes) => { - for c in &mut out[..nzeroes] { - *c = b'0'; - } - } - Part::Num(mut v) => { - for c in out[..len].iter_mut().rev() { - *c = b'0' + (v % 10) as u8; - v /= 10; - } - } - Part::Copy(buf) => { - out[..buf.len()].copy_from_slice(buf); - } - } - Some(len) - } else { - None - } - } -} - -/// Formatted result containing one or more parts. -/// This can be written to the byte buffer or converted to the allocated string. -#[allow(missing_debug_implementations)] -#[derive(Clone)] -pub struct Formatted<'a> { - /// A byte slice representing a sign, either `""`, `"-"` or `"+"`. - pub sign: &'static str, - /// Formatted parts to be rendered after a sign and optional zero padding. - pub parts: &'a [Part<'a>], -} - -impl<'a> Formatted<'a> { - /// Returns the exact byte length of combined formatted result. - pub fn len(&self) -> usize { - let mut len = self.sign.len(); - for part in self.parts { - len += part.len(); - } - len - } - - /// Writes all formatted parts into the supplied buffer. - /// Returns the number of written bytes, or `None` if the buffer is not enough. - /// (It may still leave partially written bytes in the buffer; do not rely on that.) - pub fn write(&self, out: &mut [u8]) -> Option<usize> { - if out.len() < self.sign.len() { - return None; - } - out[..self.sign.len()].copy_from_slice(self.sign.as_bytes()); - - let mut written = self.sign.len(); - for part in self.parts { - let len = part.write(&mut out[written..])?; - written += len; - } - Some(written) - } -} - /// Formats given decimal digits `0.<...buf...> * 10^exp` into the decimal form /// with at least given number of fractional digits. The result is stored to /// the supplied parts array and a slice of written parts is returned. diff --git a/library/core/src/num/fmt.rs b/library/core/src/num/fmt.rs new file mode 100644 index 00000000000..578288bda25 --- /dev/null +++ b/library/core/src/num/fmt.rs @@ -0,0 +1,108 @@ +//! Shared utilties used by both float and integer formatting. +#![doc(hidden)] +#![unstable( + feature = "numfmt", + reason = "internal routines only exposed for testing", + issue = "none" +)] + +/// Formatted parts. +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +pub enum Part<'a> { + /// Given number of zero digits. + Zero(usize), + /// A literal number up to 5 digits. + Num(u16), + /// A verbatim copy of given bytes. + Copy(&'a [u8]), +} + +impl<'a> Part<'a> { + /// Returns the exact byte length of given part. + pub fn len(&self) -> usize { + match *self { + Part::Zero(nzeroes) => nzeroes, + Part::Num(v) => { + if v < 1_000 { + if v < 10 { + 1 + } else if v < 100 { + 2 + } else { + 3 + } + } else { + if v < 10_000 { 4 } else { 5 } + } + } + Part::Copy(buf) => buf.len(), + } + } + + /// Writes a part into the supplied buffer. + /// Returns the number of written bytes, or `None` if the buffer is not enough. + /// (It may still leave partially written bytes in the buffer; do not rely on that.) + pub fn write(&self, out: &mut [u8]) -> Option<usize> { + let len = self.len(); + if out.len() >= len { + match *self { + Part::Zero(nzeroes) => { + for c in &mut out[..nzeroes] { + *c = b'0'; + } + } + Part::Num(mut v) => { + for c in out[..len].iter_mut().rev() { + *c = b'0' + (v % 10) as u8; + v /= 10; + } + } + Part::Copy(buf) => { + out[..buf.len()].copy_from_slice(buf); + } + } + Some(len) + } else { + None + } + } +} + +/// Formatted result containing one or more parts. +/// This can be written to the byte buffer or converted to the allocated string. +#[allow(missing_debug_implementations)] +#[derive(Clone)] +pub struct Formatted<'a> { + /// A byte slice representing a sign, either `""`, `"-"` or `"+"`. + pub sign: &'static str, + /// Formatted parts to be rendered after a sign and optional zero padding. + pub parts: &'a [Part<'a>], +} + +impl<'a> Formatted<'a> { + /// Returns the exact byte length of combined formatted result. + pub fn len(&self) -> usize { + let mut len = self.sign.len(); + for part in self.parts { + len += part.len(); + } + len + } + + /// Writes all formatted parts into the supplied buffer. + /// Returns the number of written bytes, or `None` if the buffer is not enough. + /// (It may still leave partially written bytes in the buffer; do not rely on that.) + pub fn write(&self, out: &mut [u8]) -> Option<usize> { + if out.len() < self.sign.len() { + return None; + } + out[..self.sign.len()].copy_from_slice(self.sign.as_bytes()); + + let mut written = self.sign.len(); + for part in self.parts { + let len = part.write(&mut out[written..])?; + written += len; + } + Some(written) + } +} diff --git a/library/core/src/num/int_log10.rs b/library/core/src/num/int_log10.rs new file mode 100644 index 00000000000..a23ca51ef87 --- /dev/null +++ b/library/core/src/num/int_log10.rs @@ -0,0 +1,134 @@ +mod unchecked { + // 0 < val <= u8::MAX + pub const fn u8(val: u8) -> u32 { + if val >= 100 { + 2 + } else if val >= 10 { + 1 + } else { + 0 + } + } + + // 0 < val <= u16::MAX + pub const fn u16(val: u16) -> u32 { + if val >= 10_000 { + 4 + } else if val >= 1000 { + 3 + } else if val >= 100 { + 2 + } else if val >= 10 { + 1 + } else { + 0 + } + } + + // 0 < val < 100_000_000 + const fn less_than_8(mut val: u32) -> u32 { + let mut log = 0; + if val >= 10_000 { + val /= 10_000; + log += 4; + } + log + if val >= 1000 { + 3 + } else if val >= 100 { + 2 + } else if val >= 10 { + 1 + } else { + 0 + } + } + + // 0 < val <= u32::MAX + pub const fn u32(mut val: u32) -> u32 { + let mut log = 0; + if val >= 100_000_000 { + val /= 100_000_000; + log += 8; + } + log + less_than_8(val) + } + + // 0 < val < 10_000_000_000_000_000 + const fn less_than_16(mut val: u64) -> u32 { + let mut log = 0; + if val >= 100_000_000 { + val /= 100_000_000; + log += 8; + } + log + less_than_8(val as u32) + } + + // 0 < val <= u64::MAX + pub const fn u64(mut val: u64) -> u32 { + let mut log = 0; + if val >= 10_000_000_000_000_000 { + val /= 10_000_000_000_000_000; + log += 16; + } + log + less_than_16(val) + } + + // 0 < val <= u128::MAX + pub const fn u128(mut val: u128) -> u32 { + let mut log = 0; + if val >= 100_000_000_000_000_000_000_000_000_000_000 { + val /= 100_000_000_000_000_000_000_000_000_000_000; + log += 32; + return log + less_than_8(val as u32); + } + if val >= 10_000_000_000_000_000 { + val /= 10_000_000_000_000_000; + log += 16; + } + log + less_than_16(val as u64) + } + + // 0 < val <= i8::MAX + pub const fn i8(val: i8) -> u32 { + u8(val as u8) + } + + // 0 < val <= i16::MAX + pub const fn i16(val: i16) -> u32 { + u16(val as u16) + } + + // 0 < val <= i32::MAX + pub const fn i32(val: i32) -> u32 { + u32(val as u32) + } + + // 0 < val <= i64::MAX + pub const fn i64(val: i64) -> u32 { + u64(val as u64) + } + + // 0 < val <= i128::MAX + pub const fn i128(val: i128) -> u32 { + u128(val as u128) + } +} + +macro_rules! impl_checked { + ($T:ident) => { + pub const fn $T(val: $T) -> Option<$T> { + if val > 0 { Some(unchecked::$T(val) as $T) } else { None } + } + }; +} + +impl_checked! { u8 } +impl_checked! { u16 } +impl_checked! { u32 } +impl_checked! { u64 } +impl_checked! { u128 } +impl_checked! { i8 } +impl_checked! { i16 } +impl_checked! { i32 } +impl_checked! { i64 } +impl_checked! { i128 } diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs index a0efe681285..0bc646995c7 100644 --- a/library/core/src/num/int_macros.rs +++ b/library/core/src/num/int_macros.rs @@ -1,9 +1,10 @@ macro_rules! int_impl { - ($SelfT:ty, $ActualT:ident, $UnsignedT:ty, $BITS:expr, $Min:expr, $Max:expr, + ($SelfT:ty, $ActualT:ident, $UnsignedT:ty, $BITS:expr, $BITS_MINUS_ONE:expr, $Min:expr, $Max:expr, $rot:expr, $rot_op:expr, $rot_result:expr, $swap_op:expr, $swapped:expr, $reversed:expr, $le_bytes:expr, $be_bytes:expr, $to_xe_bytes_doc:expr, $from_xe_bytes_doc:expr) => { - /// The smallest value that can be represented by this integer type. + /// The smallest value that can be represented by this integer type, + #[doc = concat!("-2<sup>", $BITS_MINUS_ONE, "</sup>.")] /// /// # Examples /// @@ -15,7 +16,8 @@ macro_rules! int_impl { #[stable(feature = "assoc_int_consts", since = "1.43.0")] pub const MIN: Self = !0 ^ ((!0 as $UnsignedT) >> 1) as Self; - /// The largest value that can be represented by this integer type. + /// The largest value that can be represented by this integer type, + #[doc = concat!("2<sup>", $BITS_MINUS_ONE, "</sup> - 1.")] /// /// # Examples /// @@ -1130,9 +1132,9 @@ macro_rules! int_impl { /// ``` #[stable(feature = "num_wrapping", since = "1.2.0")] #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] - #[inline] + #[inline(always)] pub const fn wrapping_neg(self) -> Self { - self.overflowing_neg().0 + (0 as $SelfT).wrapping_sub(self) } /// Panic-free bitwise shift-left; yields `self << mask(rhs)`, where `mask` removes @@ -1744,6 +1746,197 @@ macro_rules! int_impl { } } + /// Returns the logarithm of the number with respect to an arbitrary base. + /// + /// This method might not be optimized owing to implementation details; + /// `log2` can produce results more efficiently for base 2, and `log10` + /// can produce results more efficiently for base 10. + /// + /// # Panics + /// + /// When the number is zero, or if the base is not at least 2; it + /// panics in debug mode and the return value is wrapped to 0 in release + /// mode (the only situation in which the method can return 0). + /// + /// # Examples + /// + /// ``` + /// #![feature(int_log)] + #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".log(5), 1);")] + /// ``` + #[unstable(feature = "int_log", issue = "70887")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + #[track_caller] + #[rustc_inherit_overflow_checks] + #[allow(arithmetic_overflow)] + pub const fn log(self, base: Self) -> Self { + match self.checked_log(base) { + Some(n) => n, + None => { + // In debug builds, trigger a panic on None. + // This should optimize completely out in release builds. + let _ = Self::MAX + 1; + + 0 + }, + } + } + + /// Returns the base 2 logarithm of the number. + /// + /// # Panics + /// + /// When the number is zero it panics in debug mode and the return value + /// is wrapped to 0 in release mode (the only situation in which the + /// method can return 0). + /// + /// # Examples + /// + /// ``` + /// #![feature(int_log)] + #[doc = concat!("assert_eq!(2", stringify!($SelfT), ".log2(), 1);")] + /// ``` + #[unstable(feature = "int_log", issue = "70887")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + #[track_caller] + #[rustc_inherit_overflow_checks] + #[allow(arithmetic_overflow)] + pub const fn log2(self) -> Self { + match self.checked_log2() { + Some(n) => n, + None => { + // In debug builds, trigger a panic on None. + // This should optimize completely out in release builds. + let _ = Self::MAX + 1; + + 0 + }, + } + } + + /// Returns the base 10 logarithm of the number. + /// + /// # Panics + /// + /// When the number is zero it panics in debug mode and the return value + /// is wrapped to 0 in release mode (the only situation in which the + /// method can return 0). + /// + /// # Example + /// + /// ``` + /// #![feature(int_log)] + #[doc = concat!("assert_eq!(10", stringify!($SelfT), ".log10(), 1);")] + /// ``` + #[unstable(feature = "int_log", issue = "70887")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + #[track_caller] + #[rustc_inherit_overflow_checks] + #[allow(arithmetic_overflow)] + pub const fn log10(self) -> Self { + match self.checked_log10() { + Some(n) => n, + None => { + // In debug builds, trigger a panic on None. + // This should optimize completely out in release builds. + let _ = Self::MAX + 1; + + 0 + }, + } + } + + /// Returns the logarithm of the number with respect to an arbitrary base. + /// + /// Returns `None` if the number is negative or zero, or if the base is not at least 2. + /// + /// This method might not be optimized owing to implementation details; + /// `checked_log2` can produce results more efficiently for base 2, and + /// `checked_log10` can produce results more efficiently for base 10. + /// + /// # Examples + /// + /// ``` + /// #![feature(int_log)] + #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".checked_log(5), Some(1));")] + /// ``` + #[unstable(feature = "int_log", issue = "70887")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn checked_log(self, base: Self) -> Option<Self> { + if self <= 0 || base <= 1 { + None + } else { + let mut n = 0; + let mut r = self; + + // Optimization for 128 bit wide integers. + if Self::BITS == 128 { + let b = Self::log2(self) / (Self::log2(base) + 1); + n += b; + r /= base.pow(b as u32); + } + + while r >= base { + r /= base; + n += 1; + } + Some(n) + } + } + + /// Returns the base 2 logarithm of the number. + /// + /// Returns `None` if the number is negative or zero. + /// + /// # Examples + /// + /// ``` + /// #![feature(int_log)] + #[doc = concat!("assert_eq!(2", stringify!($SelfT), ".checked_log2(), Some(1));")] + /// ``` + #[unstable(feature = "int_log", issue = "70887")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn checked_log2(self) -> Option<Self> { + if self <= 0 { + None + } else { + // SAFETY: We just checked that this number is positive + let log = (Self::BITS - 1) as Self - unsafe { intrinsics::ctlz_nonzero(self) }; + Some(log) + } + } + + /// Returns the base 10 logarithm of the number. + /// + /// Returns `None` if the number is negative or zero. + /// + /// # Example + /// + /// ``` + /// #![feature(int_log)] + #[doc = concat!("assert_eq!(10", stringify!($SelfT), ".checked_log10(), Some(1));")] + /// ``` + #[unstable(feature = "int_log", issue = "70887")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn checked_log10(self) -> Option<Self> { + match int_log10::$ActualT(self as $ActualT) { + Some(s) => Some(s as Self), + None => None, + } + } + /// Computes the absolute value of `self`. /// /// # Overflow behavior @@ -1772,9 +1965,9 @@ macro_rules! int_impl { #[inline] #[rustc_inherit_overflow_checks] pub const fn abs(self) -> Self { - // Note that the #[inline] above means that the overflow - // semantics of the subtraction depend on the crate we're being - // inlined into. + // Note that the #[rustc_inherit_overflow_checks] and #[inline] + // above mean that the overflow semantics of the subtraction + // depend on the crate we're being called from. if self.is_negative() { -self } else { @@ -1905,7 +2098,7 @@ macro_rules! int_impl { #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")] // SAFETY: const sound because integers are plain old datatypes so we can always // transmute them to arrays of bytes - #[rustc_allow_const_fn_unstable(const_fn_transmute)] + #[cfg_attr(bootstrap, rustc_allow_const_fn_unstable(const_fn_transmute))] #[inline] pub const fn to_ne_bytes(self) -> [u8; mem::size_of::<Self>()] { // SAFETY: integers are plain old datatypes so we can always transmute them to @@ -2011,7 +2204,7 @@ macro_rules! int_impl { #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")] // SAFETY: const sound because integers are plain old datatypes so we can always // transmute to them - #[rustc_allow_const_fn_unstable(const_fn_transmute)] + #[cfg_attr(bootstrap, rustc_allow_const_fn_unstable(const_fn_transmute))] #[inline] pub const fn from_ne_bytes(bytes: [u8; mem::size_of::<Self>()]) -> Self { // SAFETY: integers are plain old datatypes so we can always transmute to them diff --git a/library/core/src/num/mod.rs b/library/core/src/num/mod.rs index 6032dc9a2d3..9788404dd05 100644 --- a/library/core/src/num/mod.rs +++ b/library/core/src/num/mod.rs @@ -25,10 +25,15 @@ macro_rules! unlikely { } // All these modules are technically private and only exposed for coretests: +#[cfg(not(no_fp_fmt_parse))] pub mod bignum; +#[cfg(not(no_fp_fmt_parse))] pub mod dec2flt; +#[cfg(not(no_fp_fmt_parse))] pub mod diy_float; +#[cfg(not(no_fp_fmt_parse))] pub mod flt2dec; +pub mod fmt; #[macro_use] mod int_macros; // import int_impl! @@ -36,6 +41,7 @@ mod int_macros; // import int_impl! mod uint_macros; // import uint_impl! mod error; +mod int_log10; mod nonzero; mod wrapping; @@ -43,6 +49,7 @@ mod wrapping; pub use wrapping::Wrapping; #[stable(feature = "rust1", since = "1.0.0")] +#[cfg(not(no_fp_fmt_parse))] pub use dec2flt::ParseFloatError; #[stable(feature = "rust1", since = "1.0.0")] @@ -57,12 +64,7 @@ pub use nonzero::{NonZeroI128, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, No #[stable(feature = "try_from", since = "1.34.0")] pub use error::TryFromIntError; -#[unstable( - feature = "int_error_matching", - reason = "it can be useful to match errors when making error messages \ - for integer parsing", - issue = "22639" -)] +#[stable(feature = "int_error_matching", since = "1.55.0")] pub use error::IntErrorKind; macro_rules! usize_isize_to_xe_bytes_doc { @@ -89,26 +91,26 @@ depending on the target pointer size. #[lang = "i8"] impl i8 { - int_impl! { i8, i8, u8, 8, -128, 127, 2, "-0x7e", "0xa", "0x12", "0x12", "0x48", + int_impl! { i8, i8, u8, 8, 7, -128, 127, 2, "-0x7e", "0xa", "0x12", "0x12", "0x48", "[0x12]", "[0x12]", "", "" } } #[lang = "i16"] impl i16 { - int_impl! { i16, i16, u16, 16, -32768, 32767, 4, "-0x5ffd", "0x3a", "0x1234", "0x3412", + int_impl! { i16, i16, u16, 16, 15, -32768, 32767, 4, "-0x5ffd", "0x3a", "0x1234", "0x3412", "0x2c48", "[0x34, 0x12]", "[0x12, 0x34]", "", "" } } #[lang = "i32"] impl i32 { - int_impl! { i32, i32, u32, 32, -2147483648, 2147483647, 8, "0x10000b3", "0xb301", + int_impl! { i32, i32, u32, 32, 31, -2147483648, 2147483647, 8, "0x10000b3", "0xb301", "0x12345678", "0x78563412", "0x1e6a2c48", "[0x78, 0x56, 0x34, 0x12]", "[0x12, 0x34, 0x56, 0x78]", "", "" } } #[lang = "i64"] impl i64 { - int_impl! { i64, i64, u64, 64, -9223372036854775808, 9223372036854775807, 12, + int_impl! { i64, i64, u64, 64, 63, -9223372036854775808, 9223372036854775807, 12, "0xaa00000000006e1", "0x6e10aa", "0x1234567890123456", "0x5634129078563412", "0x6a2c48091e6a2c48", "[0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12]", "[0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56]", "", "" } @@ -116,7 +118,7 @@ impl i64 { #[lang = "i128"] impl i128 { - int_impl! { i128, i128, u128, 128, -170141183460469231731687303715884105728, + int_impl! { i128, i128, u128, 128, 127, -170141183460469231731687303715884105728, 170141183460469231731687303715884105727, 16, "0x13f40000000000000000000000004f76", "0x4f7613f4", "0x12345678901234567890123456789012", "0x12907856341290785634129078563412", "0x48091e6a2c48091e6a2c48091e6a2c48", @@ -129,7 +131,7 @@ impl i128 { #[cfg(target_pointer_width = "16")] #[lang = "isize"] impl isize { - int_impl! { isize, i16, usize, 16, -32768, 32767, 4, "-0x5ffd", "0x3a", "0x1234", + int_impl! { isize, i16, usize, 16, 15, -32768, 32767, 4, "-0x5ffd", "0x3a", "0x1234", "0x3412", "0x2c48", "[0x34, 0x12]", "[0x12, 0x34]", usize_isize_to_xe_bytes_doc!(), usize_isize_from_xe_bytes_doc!() } } @@ -137,7 +139,7 @@ impl isize { #[cfg(target_pointer_width = "32")] #[lang = "isize"] impl isize { - int_impl! { isize, i32, usize, 32, -2147483648, 2147483647, 8, "0x10000b3", "0xb301", + int_impl! { isize, i32, usize, 32, 31, -2147483648, 2147483647, 8, "0x10000b3", "0xb301", "0x12345678", "0x78563412", "0x1e6a2c48", "[0x78, 0x56, 0x34, 0x12]", "[0x12, 0x34, 0x56, 0x78]", usize_isize_to_xe_bytes_doc!(), usize_isize_from_xe_bytes_doc!() } @@ -146,7 +148,7 @@ impl isize { #[cfg(target_pointer_width = "64")] #[lang = "isize"] impl isize { - int_impl! { isize, i64, usize, 64, -9223372036854775808, 9223372036854775807, + int_impl! { isize, i64, usize, 64, 63, -9223372036854775808, 9223372036854775807, 12, "0xaa00000000006e1", "0x6e10aa", "0x1234567890123456", "0x5634129078563412", "0x6a2c48091e6a2c48", "[0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12]", "[0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56]", @@ -595,8 +597,8 @@ impl u8 { /// before using this function. /// /// [infra-aw]: https://infra.spec.whatwg.org/#ascii-whitespace - /// [pct]: http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap07.html#tag_07_03_01 - /// [bfs]: http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_06_05 + /// [pct]: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap07.html#tag_07_03_01 + /// [bfs]: https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_06_05 /// /// # Examples /// @@ -845,7 +847,7 @@ fn from_str_radix<T: FromStrRadixHelper>(src: &str, radix: u32) -> Result<T, Par use self::ParseIntError as PIE; assert!( - radix >= 2 && radix <= 36, + (2..=36).contains(&radix), "from_str_radix_int: must lie in the range `[2, 36]` - found {}", radix ); diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs index 6b9b435d47f..dd9b9330aee 100644 --- a/library/core/src/num/nonzero.rs +++ b/library/core/src/num/nonzero.rs @@ -42,7 +42,8 @@ macro_rules! nonzero_integers { pub struct $Ty($Int); impl $Ty { - /// Creates a non-zero without checking the value. + /// Creates a non-zero without checking whether the value is non-zero. + /// This results in undefined behaviour if the value is zero. /// /// # Safety /// @@ -285,6 +286,576 @@ nonzero_integers_div! { NonZeroUsize(usize); } +// A bunch of methods for unsigned nonzero types only. +macro_rules! nonzero_unsigned_operations { + ( $( $Ty: ident($Int: ty); )+ ) => { + $( + impl $Ty { + /// Add an unsigned integer to a non-zero value. + /// Check for overflow and return [`None`] on overflow + /// As a consequence, the result cannot wrap to zero. + /// + /// + /// # Examples + /// + /// ``` + /// #![feature(nonzero_ops)] + #[doc = concat!("# use std::num::", stringify!($Ty), ";")] + /// + /// # fn main() { test().unwrap(); } + /// # fn test() -> Option<()> { + #[doc = concat!("let one = ", stringify!($Ty), "::new(1)?;")] + #[doc = concat!("let two = ", stringify!($Ty), "::new(2)?;")] + #[doc = concat!("let max = ", stringify!($Ty), "::new(", + stringify!($Int), "::MAX)?;")] + /// + /// assert_eq!(Some(two), one.checked_add(1)); + /// assert_eq!(None, max.checked_add(1)); + /// # Some(()) + /// # } + /// ``` + #[unstable(feature = "nonzero_ops", issue = "84186")] + #[inline] + pub const fn checked_add(self, other: $Int) -> Option<$Ty> { + if let Some(result) = self.get().checked_add(other) { + // SAFETY: $Int::checked_add returns None on overflow + // so the result cannot be zero. + Some(unsafe { $Ty::new_unchecked(result) }) + } else { + None + } + } + + /// Add an unsigned integer to a non-zero value. + #[doc = concat!("Return [`", stringify!($Int), "::MAX`] on overflow.")] + /// + /// # Examples + /// + /// ``` + /// #![feature(nonzero_ops)] + #[doc = concat!("# use std::num::", stringify!($Ty), ";")] + /// + /// # fn main() { test().unwrap(); } + /// # fn test() -> Option<()> { + #[doc = concat!("let one = ", stringify!($Ty), "::new(1)?;")] + #[doc = concat!("let two = ", stringify!($Ty), "::new(2)?;")] + #[doc = concat!("let max = ", stringify!($Ty), "::new(", + stringify!($Int), "::MAX)?;")] + /// + /// assert_eq!(two, one.saturating_add(1)); + /// assert_eq!(max, max.saturating_add(1)); + /// # Some(()) + /// # } + /// ``` + #[unstable(feature = "nonzero_ops", issue = "84186")] + #[inline] + pub const fn saturating_add(self, other: $Int) -> $Ty { + // SAFETY: $Int::saturating_add returns $Int::MAX on overflow + // so the result cannot be zero. + unsafe { $Ty::new_unchecked(self.get().saturating_add(other)) } + } + + /// Add an unsigned integer to a non-zero value, + /// assuming overflow cannot occur. + /// Overflow is unchecked, and it is undefined behaviour to overflow + /// *even if the result would wrap to a non-zero value*. + /// The behaviour is undefined as soon as + #[doc = concat!("`self + rhs > ", stringify!($Int), "::MAX`.")] + /// + /// # Examples + /// + /// ``` + /// #![feature(nonzero_ops)] + #[doc = concat!("# use std::num::", stringify!($Ty), ";")] + /// + /// # fn main() { test().unwrap(); } + /// # fn test() -> Option<()> { + #[doc = concat!("let one = ", stringify!($Ty), "::new(1)?;")] + #[doc = concat!("let two = ", stringify!($Ty), "::new(2)?;")] + /// + /// assert_eq!(two, unsafe { one.unchecked_add(1) }); + /// # Some(()) + /// # } + /// ``` + #[unstable(feature = "nonzero_ops", issue = "84186")] + #[inline] + pub unsafe fn unchecked_add(self, other: $Int) -> $Ty { + // SAFETY: The caller ensures there is no overflow. + unsafe { $Ty::new_unchecked(self.get().unchecked_add(other)) } + } + + /// Returns the smallest power of two greater than or equal to n. + /// Check for overflow and return [`None`] + /// if the next power of two is greater than the type’s maximum value. + /// As a consequence, the result cannot wrap to zero. + /// + /// # Examples + /// + /// ``` + /// #![feature(nonzero_ops)] + #[doc = concat!("# use std::num::", stringify!($Ty), ";")] + /// + /// # fn main() { test().unwrap(); } + /// # fn test() -> Option<()> { + #[doc = concat!("let two = ", stringify!($Ty), "::new(2)?;")] + #[doc = concat!("let three = ", stringify!($Ty), "::new(3)?;")] + #[doc = concat!("let four = ", stringify!($Ty), "::new(4)?;")] + #[doc = concat!("let max = ", stringify!($Ty), "::new(", + stringify!($Int), "::MAX)?;")] + /// + /// assert_eq!(Some(two), two.checked_next_power_of_two() ); + /// assert_eq!(Some(four), three.checked_next_power_of_two() ); + /// assert_eq!(None, max.checked_next_power_of_two() ); + /// # Some(()) + /// # } + /// ``` + #[unstable(feature = "nonzero_ops", issue = "84186")] + #[inline] + pub const fn checked_next_power_of_two(self) -> Option<$Ty> { + if let Some(nz) = self.get().checked_next_power_of_two() { + // SAFETY: The next power of two is positive + // and overflow is checked. + Some(unsafe { $Ty::new_unchecked(nz) }) + } else { + None + } + } + } + )+ + } +} + +nonzero_unsigned_operations! { + NonZeroU8(u8); + NonZeroU16(u16); + NonZeroU32(u32); + NonZeroU64(u64); + NonZeroU128(u128); + NonZeroUsize(usize); +} + +// A bunch of methods for signed nonzero types only. +macro_rules! nonzero_signed_operations { + ( $( $Ty: ident($Int: ty) -> $Uty: ident($Uint: ty); )+ ) => { + $( + impl $Ty { + /// Computes the absolute value of self. + #[doc = concat!("See [`", stringify!($Int), "::abs`]")] + /// for documentation on overflow behaviour. + /// + /// # Example + /// + /// ``` + /// #![feature(nonzero_ops)] + #[doc = concat!("# use std::num::", stringify!($Ty), ";")] + /// + /// # fn main() { test().unwrap(); } + /// # fn test() -> Option<()> { + #[doc = concat!("let pos = ", stringify!($Ty), "::new(1)?;")] + #[doc = concat!("let neg = ", stringify!($Ty), "::new(-1)?;")] + /// + /// assert_eq!(pos, pos.abs()); + /// assert_eq!(pos, neg.abs()); + /// # Some(()) + /// # } + /// ``` + #[unstable(feature = "nonzero_ops", issue = "84186")] + #[inline] + pub const fn abs(self) -> $Ty { + // SAFETY: This cannot overflow to zero. + unsafe { $Ty::new_unchecked(self.get().abs()) } + } + + /// Checked absolute value. + /// Check for overflow and returns [`None`] if + #[doc = concat!("`self == ", stringify!($Int), "::MIN`.")] + /// The result cannot be zero. + /// + /// # Example + /// + /// ``` + /// #![feature(nonzero_ops)] + #[doc = concat!("# use std::num::", stringify!($Ty), ";")] + /// + /// # fn main() { test().unwrap(); } + /// # fn test() -> Option<()> { + #[doc = concat!("let pos = ", stringify!($Ty), "::new(1)?;")] + #[doc = concat!("let neg = ", stringify!($Ty), "::new(-1)?;")] + #[doc = concat!("let min = ", stringify!($Ty), "::new(", + stringify!($Int), "::MIN)?;")] + /// + /// assert_eq!(Some(pos), neg.checked_abs()); + /// assert_eq!(None, min.checked_abs()); + /// # Some(()) + /// # } + /// ``` + #[unstable(feature = "nonzero_ops", issue = "84186")] + #[inline] + pub const fn checked_abs(self) -> Option<$Ty> { + if let Some(nz) = self.get().checked_abs() { + // SAFETY: absolute value of nonzero cannot yield zero values. + Some(unsafe { $Ty::new_unchecked(nz) }) + } else { + None + } + } + + /// Computes the absolute value of self, + /// with overflow information, see + #[doc = concat!("[`", stringify!($Int), "::overflowing_abs`].")] + /// + /// # Example + /// + /// ``` + /// #![feature(nonzero_ops)] + #[doc = concat!("# use std::num::", stringify!($Ty), ";")] + /// + /// # fn main() { test().unwrap(); } + /// # fn test() -> Option<()> { + #[doc = concat!("let pos = ", stringify!($Ty), "::new(1)?;")] + #[doc = concat!("let neg = ", stringify!($Ty), "::new(-1)?;")] + #[doc = concat!("let min = ", stringify!($Ty), "::new(", + stringify!($Int), "::MIN)?;")] + /// + /// assert_eq!((pos, false), pos.overflowing_abs()); + /// assert_eq!((pos, false), neg.overflowing_abs()); + /// assert_eq!((min, true), min.overflowing_abs()); + /// # Some(()) + /// # } + /// ``` + #[unstable(feature = "nonzero_ops", issue = "84186")] + #[inline] + pub const fn overflowing_abs(self) -> ($Ty, bool) { + let (nz, flag) = self.get().overflowing_abs(); + ( + // SAFETY: absolute value of nonzero cannot yield zero values. + unsafe { $Ty::new_unchecked(nz) }, + flag, + ) + } + + /// Saturating absolute value, see + #[doc = concat!("[`", stringify!($Int), "::saturating_abs`].")] + /// + /// # Example + /// + /// ``` + /// #![feature(nonzero_ops)] + #[doc = concat!("# use std::num::", stringify!($Ty), ";")] + /// + /// # fn main() { test().unwrap(); } + /// # fn test() -> Option<()> { + #[doc = concat!("let pos = ", stringify!($Ty), "::new(1)?;")] + #[doc = concat!("let neg = ", stringify!($Ty), "::new(-1)?;")] + #[doc = concat!("let min = ", stringify!($Ty), "::new(", + stringify!($Int), "::MIN)?;")] + #[doc = concat!("let min_plus = ", stringify!($Ty), "::new(", + stringify!($Int), "::MIN + 1)?;")] + #[doc = concat!("let max = ", stringify!($Ty), "::new(", + stringify!($Int), "::MAX)?;")] + /// + /// assert_eq!(pos, pos.saturating_abs()); + /// assert_eq!(pos, neg.saturating_abs()); + /// assert_eq!(max, min.saturating_abs()); + /// assert_eq!(max, min_plus.saturating_abs()); + /// # Some(()) + /// # } + /// ``` + #[unstable(feature = "nonzero_ops", issue = "84186")] + #[inline] + pub const fn saturating_abs(self) -> $Ty { + // SAFETY: absolute value of nonzero cannot yield zero values. + unsafe { $Ty::new_unchecked(self.get().saturating_abs()) } + } + + /// Wrapping absolute value, see + #[doc = concat!("[`", stringify!($Int), "::wrapping_abs`].")] + /// + /// # Example + /// + /// ``` + /// #![feature(nonzero_ops)] + #[doc = concat!("# use std::num::", stringify!($Ty), ";")] + /// + /// # fn main() { test().unwrap(); } + /// # fn test() -> Option<()> { + #[doc = concat!("let pos = ", stringify!($Ty), "::new(1)?;")] + #[doc = concat!("let neg = ", stringify!($Ty), "::new(-1)?;")] + #[doc = concat!("let min = ", stringify!($Ty), "::new(", + stringify!($Int), "::MIN)?;")] + #[doc = concat!("let max = ", stringify!($Ty), "::new(", + stringify!($Int), "::MAX)?;")] + /// + /// assert_eq!(pos, pos.wrapping_abs()); + /// assert_eq!(pos, neg.wrapping_abs()); + /// assert_eq!(min, min.wrapping_abs()); + /// # // FIXME: add once Neg is implemented? + /// # // assert_eq!(max, (-max).wrapping_abs()); + /// # Some(()) + /// # } + /// ``` + #[unstable(feature = "nonzero_ops", issue = "84186")] + #[inline] + pub const fn wrapping_abs(self) -> $Ty { + // SAFETY: absolute value of nonzero cannot yield zero values. + unsafe { $Ty::new_unchecked(self.get().wrapping_abs()) } + } + + /// Computes the absolute value of self + /// without any wrapping or panicking. + /// + /// # Example + /// + /// ``` + /// #![feature(nonzero_ops)] + #[doc = concat!("# use std::num::", stringify!($Ty), ";")] + #[doc = concat!("# use std::num::", stringify!($Uty), ";")] + /// + /// # fn main() { test().unwrap(); } + /// # fn test() -> Option<()> { + #[doc = concat!("let u_pos = ", stringify!($Uty), "::new(1)?;")] + #[doc = concat!("let i_pos = ", stringify!($Ty), "::new(1)?;")] + #[doc = concat!("let i_neg = ", stringify!($Ty), "::new(-1)?;")] + #[doc = concat!("let i_min = ", stringify!($Ty), "::new(", + stringify!($Int), "::MIN)?;")] + #[doc = concat!("let u_max = ", stringify!($Uty), "::new(", + stringify!($Uint), "::MAX / 2 + 1)?;")] + /// + /// assert_eq!(u_pos, i_pos.unsigned_abs()); + /// assert_eq!(u_pos, i_neg.unsigned_abs()); + /// assert_eq!(u_max, i_min.unsigned_abs()); + /// # Some(()) + /// # } + /// ``` + #[unstable(feature = "nonzero_ops", issue = "84186")] + #[inline] + pub const fn unsigned_abs(self) -> $Uty { + // SAFETY: absolute value of nonzero cannot yield zero values. + unsafe { $Uty::new_unchecked(self.get().unsigned_abs()) } + } + } + )+ + } +} + +nonzero_signed_operations! { + NonZeroI8(i8) -> NonZeroU8(u8); + NonZeroI16(i16) -> NonZeroU16(u16); + NonZeroI32(i32) -> NonZeroU32(u32); + NonZeroI64(i64) -> NonZeroU64(u64); + NonZeroI128(i128) -> NonZeroU128(u128); + NonZeroIsize(isize) -> NonZeroUsize(usize); +} + +// A bunch of methods for both signed and unsigned nonzero types. +macro_rules! nonzero_unsigned_signed_operations { + ( $( $signedness:ident $Ty: ident($Int: ty); )+ ) => { + $( + impl $Ty { + /// Multiply two non-zero integers together. + /// Check for overflow and return [`None`] on overflow. + /// As a consequence, the result cannot wrap to zero. + /// + /// # Examples + /// + /// ``` + /// #![feature(nonzero_ops)] + #[doc = concat!("# use std::num::", stringify!($Ty), ";")] + /// + /// # fn main() { test().unwrap(); } + /// # fn test() -> Option<()> { + #[doc = concat!("let two = ", stringify!($Ty), "::new(2)?;")] + #[doc = concat!("let four = ", stringify!($Ty), "::new(4)?;")] + #[doc = concat!("let max = ", stringify!($Ty), "::new(", + stringify!($Int), "::MAX)?;")] + /// + /// assert_eq!(Some(four), two.checked_mul(two)); + /// assert_eq!(None, max.checked_mul(two)); + /// # Some(()) + /// # } + /// ``` + #[unstable(feature = "nonzero_ops", issue = "84186")] + #[inline] + pub const fn checked_mul(self, other: $Ty) -> Option<$Ty> { + if let Some(result) = self.get().checked_mul(other.get()) { + // SAFETY: checked_mul returns None on overflow + // and `other` is also non-null + // so the result cannot be zero. + Some(unsafe { $Ty::new_unchecked(result) }) + } else { + None + } + } + + /// Multiply two non-zero integers together. + #[doc = concat!("Return [`", stringify!($Int), "::MAX`] on overflow.")] + /// + /// # Examples + /// + /// ``` + /// #![feature(nonzero_ops)] + #[doc = concat!("# use std::num::", stringify!($Ty), ";")] + /// + /// # fn main() { test().unwrap(); } + /// # fn test() -> Option<()> { + #[doc = concat!("let two = ", stringify!($Ty), "::new(2)?;")] + #[doc = concat!("let four = ", stringify!($Ty), "::new(4)?;")] + #[doc = concat!("let max = ", stringify!($Ty), "::new(", + stringify!($Int), "::MAX)?;")] + /// + /// assert_eq!(four, two.saturating_mul(two)); + /// assert_eq!(max, four.saturating_mul(max)); + /// # Some(()) + /// # } + /// ``` + #[unstable(feature = "nonzero_ops", issue = "84186")] + #[inline] + pub const fn saturating_mul(self, other: $Ty) -> $Ty { + // SAFETY: saturating_mul returns u*::MAX on overflow + // and `other` is also non-null + // so the result cannot be zero. + unsafe { $Ty::new_unchecked(self.get().saturating_mul(other.get())) } + } + + /// Multiply two non-zero integers together, + /// assuming overflow cannot occur. + /// Overflow is unchecked, and it is undefined behaviour to overflow + /// *even if the result would wrap to a non-zero value*. + /// The behaviour is undefined as soon as + #[doc = sign_dependent_expr!{ + $signedness ? + if signed { + concat!("`self * rhs > ", stringify!($Int), "::MAX`, ", + "or `self * rhs < ", stringify!($Int), "::MIN`.") + } + if unsigned { + concat!("`self * rhs > ", stringify!($Int), "::MAX`.") + } + }] + /// + /// # Examples + /// + /// ``` + /// #![feature(nonzero_ops)] + #[doc = concat!("# use std::num::", stringify!($Ty), ";")] + /// + /// # fn main() { test().unwrap(); } + /// # fn test() -> Option<()> { + #[doc = concat!("let two = ", stringify!($Ty), "::new(2)?;")] + #[doc = concat!("let four = ", stringify!($Ty), "::new(4)?;")] + /// + /// assert_eq!(four, unsafe { two.unchecked_mul(two) }); + /// # Some(()) + /// # } + /// ``` + #[unstable(feature = "nonzero_ops", issue = "84186")] + #[inline] + pub unsafe fn unchecked_mul(self, other: $Ty) -> $Ty { + // SAFETY: The caller ensures there is no overflow. + unsafe { $Ty::new_unchecked(self.get().unchecked_mul(other.get())) } + } + + /// Raise non-zero value to an integer power. + /// Check for overflow and return [`None`] on overflow. + /// As a consequence, the result cannot wrap to zero. + /// + /// # Examples + /// + /// ``` + /// #![feature(nonzero_ops)] + #[doc = concat!("# use std::num::", stringify!($Ty), ";")] + /// + /// # fn main() { test().unwrap(); } + /// # fn test() -> Option<()> { + #[doc = concat!("let three = ", stringify!($Ty), "::new(3)?;")] + #[doc = concat!("let twenty_seven = ", stringify!($Ty), "::new(27)?;")] + #[doc = concat!("let half_max = ", stringify!($Ty), "::new(", + stringify!($Int), "::MAX / 2)?;")] + /// + /// assert_eq!(Some(twenty_seven), three.checked_pow(3)); + /// assert_eq!(None, half_max.checked_pow(3)); + /// # Some(()) + /// # } + /// ``` + #[unstable(feature = "nonzero_ops", issue = "84186")] + #[inline] + pub const fn checked_pow(self, other: u32) -> Option<$Ty> { + if let Some(result) = self.get().checked_pow(other) { + // SAFETY: checked_pow returns None on overflow + // so the result cannot be zero. + Some(unsafe { $Ty::new_unchecked(result) }) + } else { + None + } + } + + /// Raise non-zero value to an integer power. + #[doc = sign_dependent_expr!{ + $signedness ? + if signed { + concat!("Return [`", stringify!($Int), "::MIN`] ", + "or [`", stringify!($Int), "::MAX`] on overflow.") + } + if unsigned { + concat!("Return [`", stringify!($Int), "::MAX`] on overflow.") + } + }] + /// + /// # Examples + /// + /// ``` + /// #![feature(nonzero_ops)] + #[doc = concat!("# use std::num::", stringify!($Ty), ";")] + /// + /// # fn main() { test().unwrap(); } + /// # fn test() -> Option<()> { + #[doc = concat!("let three = ", stringify!($Ty), "::new(3)?;")] + #[doc = concat!("let twenty_seven = ", stringify!($Ty), "::new(27)?;")] + #[doc = concat!("let max = ", stringify!($Ty), "::new(", + stringify!($Int), "::MAX)?;")] + /// + /// assert_eq!(twenty_seven, three.saturating_pow(3)); + /// assert_eq!(max, max.saturating_pow(3)); + /// # Some(()) + /// # } + /// ``` + #[unstable(feature = "nonzero_ops", issue = "84186")] + #[inline] + pub const fn saturating_pow(self, other: u32) -> $Ty { + // SAFETY: saturating_pow returns u*::MAX on overflow + // so the result cannot be zero. + unsafe { $Ty::new_unchecked(self.get().saturating_pow(other)) } + } + } + )+ + } +} + +// Use this when the generated code should differ between signed and unsigned types. +macro_rules! sign_dependent_expr { + (signed ? if signed { $signed_case:expr } if unsigned { $unsigned_case:expr } ) => { + $signed_case + }; + (unsigned ? if signed { $signed_case:expr } if unsigned { $unsigned_case:expr } ) => { + $unsigned_case + }; +} + +nonzero_unsigned_signed_operations! { + unsigned NonZeroU8(u8); + unsigned NonZeroU16(u16); + unsigned NonZeroU32(u32); + unsigned NonZeroU64(u64); + unsigned NonZeroU128(u128); + unsigned NonZeroUsize(usize); + signed NonZeroI8(i8); + signed NonZeroI16(i16); + signed NonZeroI32(i32); + signed NonZeroI64(i64); + signed NonZeroI128(i128); + signed NonZeroIsize(isize); +} + macro_rules! nonzero_unsigned_is_power_of_two { ( $( $Ty: ident )+ ) => { $( diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs index e512d90ef37..ae113a47e95 100644 --- a/library/core/src/num/uint_macros.rs +++ b/library/core/src/num/uint_macros.rs @@ -1,5 +1,5 @@ macro_rules! uint_impl { - ($SelfT:ty, $ActualT:ty, $BITS:expr, $MaxV:expr, + ($SelfT:ty, $ActualT:ident, $BITS:expr, $MaxV:expr, $rot:expr, $rot_op:expr, $rot_result:expr, $swap_op:expr, $swapped:expr, $reversed:expr, $le_bytes:expr, $be_bytes:expr, $to_xe_bytes_doc:expr, $from_xe_bytes_doc:expr) => { @@ -15,7 +15,8 @@ macro_rules! uint_impl { #[stable(feature = "assoc_int_consts", since = "1.43.0")] pub const MIN: Self = 0; - /// The largest value that can be represented by this integer type. + /// The largest value that can be represented by this integer type, + #[doc = concat!("2<sup>", $BITS, "</sup> - 1.")] /// /// # Examples /// @@ -634,6 +635,197 @@ macro_rules! uint_impl { } } + /// Returns the logarithm of the number with respect to an arbitrary base. + /// + /// This method might not be optimized owing to implementation details; + /// `log2` can produce results more efficiently for base 2, and `log10` + /// can produce results more efficiently for base 10. + /// + /// # Panics + /// + /// When the number is negative, zero, or if the base is not at least 2; + /// it panics in debug mode and the return value is wrapped to 0 in + /// release mode (the only situation in which the method can return 0). + /// + /// # Examples + /// + /// ``` + /// #![feature(int_log)] + #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".log(5), 1);")] + /// ``` + #[unstable(feature = "int_log", issue = "70887")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + #[track_caller] + #[rustc_inherit_overflow_checks] + #[allow(arithmetic_overflow)] + pub const fn log(self, base: Self) -> Self { + match self.checked_log(base) { + Some(n) => n, + None => { + // In debug builds, trigger a panic on None. + // This should optimize completely out in release builds. + let _ = Self::MAX + 1; + + 0 + }, + } + } + + /// Returns the base 2 logarithm of the number. + /// + /// # Panics + /// + /// When the number is negative or zero it panics in debug mode and + /// the return value is wrapped to 0 in release mode (the only situation in + /// which the method can return 0). + /// + /// # Examples + /// + /// ``` + /// #![feature(int_log)] + #[doc = concat!("assert_eq!(2", stringify!($SelfT), ".log2(), 1);")] + /// ``` + #[unstable(feature = "int_log", issue = "70887")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + #[track_caller] + #[rustc_inherit_overflow_checks] + #[allow(arithmetic_overflow)] + pub const fn log2(self) -> Self { + match self.checked_log2() { + Some(n) => n, + None => { + // In debug builds, trigger a panic on None. + // This should optimize completely out in release builds. + let _ = Self::MAX + 1; + + 0 + }, + } + } + + /// Returns the base 10 logarithm of the number. + /// + /// # Panics + /// + /// When the number is negative or zero it panics in debug mode and the + /// return value is wrapped to 0 in release mode (the only situation in + /// which the method can return 0). + /// + /// # Example + /// + /// ``` + /// #![feature(int_log)] + #[doc = concat!("assert_eq!(10", stringify!($SelfT), ".log10(), 1);")] + /// ``` + #[unstable(feature = "int_log", issue = "70887")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + #[track_caller] + #[rustc_inherit_overflow_checks] + #[allow(arithmetic_overflow)] + pub const fn log10(self) -> Self { + match self.checked_log10() { + Some(n) => n, + None => { + // In debug builds, trigger a panic on None. + // This should optimize completely out in release builds. + let _ = Self::MAX + 1; + + 0 + }, + } + } + + /// Returns the logarithm of the number with respect to an arbitrary base. + /// + /// Returns `None` if the number is zero, or if the base is not at least 2. + /// + /// This method might not be optimized owing to implementation details; + /// `checked_log2` can produce results more efficiently for base 2, and + /// `checked_log10` can produce results more efficiently for base 10. + /// + /// # Examples + /// + /// ``` + /// #![feature(int_log)] + #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".checked_log(5), Some(1));")] + /// ``` + #[unstable(feature = "int_log", issue = "70887")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn checked_log(self, base: Self) -> Option<Self> { + if self <= 0 || base <= 1 { + None + } else { + let mut n = 0; + let mut r = self; + + // Optimization for 128 bit wide integers. + if Self::BITS == 128 { + let b = Self::log2(self) / (Self::log2(base) + 1); + n += b; + r /= base.pow(b as u32); + } + + while r >= base { + r /= base; + n += 1; + } + Some(n) + } + } + + /// Returns the base 2 logarithm of the number. + /// + /// Returns `None` if the number is zero. + /// + /// # Examples + /// + /// ``` + /// #![feature(int_log)] + #[doc = concat!("assert_eq!(2", stringify!($SelfT), ".checked_log2(), Some(1));")] + /// ``` + #[unstable(feature = "int_log", issue = "70887")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn checked_log2(self) -> Option<Self> { + if self <= 0 { + None + } else { + // SAFETY: We just checked that this number is positive + let log = (Self::BITS - 1) as Self - unsafe { intrinsics::ctlz_nonzero(self) }; + Some(log) + } + } + + /// Returns the base 10 logarithm of the number. + /// + /// Returns `None` if the number is zero. + /// + /// # Examples + /// + /// ``` + /// #![feature(int_log)] + #[doc = concat!("assert_eq!(10", stringify!($SelfT), ".checked_log10(), Some(1));")] + /// ``` + #[unstable(feature = "int_log", issue = "70887")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn checked_log10(self) -> Option<Self> { + match int_log10::$ActualT(self as $ActualT) { + Some(s) => Some(s as Self), + None => None, + } + } + /// Checked negation. Computes `-self`, returning `None` unless `self == /// 0`. /// @@ -1054,9 +1246,9 @@ macro_rules! uint_impl { /// ``` #[stable(feature = "num_wrapping", since = "1.2.0")] #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")] - #[inline] + #[inline(always)] pub const fn wrapping_neg(self) -> Self { - self.overflowing_neg().0 + (0 as $SelfT).wrapping_sub(self) } /// Panic-free bitwise shift-left; yields `self << mask(rhs)`, @@ -1735,7 +1927,7 @@ macro_rules! uint_impl { #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")] // SAFETY: const sound because integers are plain old datatypes so we can always // transmute them to arrays of bytes - #[rustc_allow_const_fn_unstable(const_fn_transmute)] + #[cfg_attr(bootstrap, rustc_allow_const_fn_unstable(const_fn_transmute))] #[inline] pub const fn to_ne_bytes(self) -> [u8; mem::size_of::<Self>()] { // SAFETY: integers are plain old datatypes so we can always transmute them to @@ -1841,7 +2033,7 @@ macro_rules! uint_impl { #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")] // SAFETY: const sound because integers are plain old datatypes so we can always // transmute to them - #[rustc_allow_const_fn_unstable(const_fn_transmute)] + #[cfg_attr(bootstrap, rustc_allow_const_fn_unstable(const_fn_transmute))] #[inline] pub const fn from_ne_bytes(bytes: [u8; mem::size_of::<Self>()]) -> Self { // SAFETY: integers are plain old datatypes so we can always transmute to them diff --git a/library/core/src/ops/control_flow.rs b/library/core/src/ops/control_flow.rs index 9d9398fb56d..c2270c864df 100644 --- a/library/core/src/ops/control_flow.rs +++ b/library/core/src/ops/control_flow.rs @@ -11,7 +11,6 @@ use crate::{convert, ops}; /// /// Early-exiting from [`Iterator::try_for_each`]: /// ``` -/// #![feature(control_flow_enum)] /// use std::ops::ControlFlow; /// /// let r = (2..100).try_for_each(|x| { @@ -26,7 +25,6 @@ use crate::{convert, ops}; /// /// A basic tree traversal: /// ```no_run -/// #![feature(control_flow_enum)] /// use std::ops::ControlFlow; /// /// pub struct TreeNode<T> { @@ -48,42 +46,22 @@ use crate::{convert, ops}; /// } /// } /// ``` -#[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")] +#[stable(feature = "control_flow_enum_type", since = "1.55.0")] #[derive(Debug, Clone, Copy, PartialEq)] pub enum ControlFlow<B, C = ()> { /// Move on to the next phase of the operation as normal. - #[cfg_attr(not(bootstrap), lang = "Continue")] + #[stable(feature = "control_flow_enum_type", since = "1.55.0")] + #[lang = "Continue"] Continue(C), /// Exit the operation without running subsequent phases. - #[cfg_attr(not(bootstrap), lang = "Break")] + #[stable(feature = "control_flow_enum_type", since = "1.55.0")] + #[lang = "Break"] Break(B), // Yes, the order of the variants doesn't match the type parameters. // They're in this order so that `ControlFlow<A, B>` <-> `Result<B, A>` // is a no-op conversion in the `Try` implementation. } -#[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")] -#[cfg(bootstrap)] -impl<B, C> ops::TryV1 for ControlFlow<B, C> { - type Output = C; - type Error = B; - #[inline] - fn into_result(self) -> Result<Self::Output, Self::Error> { - match self { - ControlFlow::Continue(y) => Ok(y), - ControlFlow::Break(x) => Err(x), - } - } - #[inline] - fn from_error(v: Self::Error) -> Self { - ControlFlow::Break(v) - } - #[inline] - fn from_ok(v: Self::Output) -> Self { - ControlFlow::Continue(v) - } -} - #[unstable(feature = "try_trait_v2", issue = "84277")] impl<B, C> ops::TryV2 for ControlFlow<B, C> { type Output = C; @@ -184,31 +162,9 @@ impl<B, C> ControlFlow<B, C> { } } -#[cfg(bootstrap)] -impl<R: ops::TryV1> ControlFlow<R, R::Output> { - /// Create a `ControlFlow` from any type implementing `Try`. - #[inline] - pub(crate) fn from_try(r: R) -> Self { - match R::into_result(r) { - Ok(v) => ControlFlow::Continue(v), - Err(v) => ControlFlow::Break(R::from_error(v)), - } - } - - /// Convert a `ControlFlow` into any type implementing `Try`; - #[inline] - pub(crate) fn into_try(self) -> R { - match self { - ControlFlow::Continue(v) => R::from_ok(v), - ControlFlow::Break(v) => v, - } - } -} - /// These are used only as part of implementing the iterator adapters. /// They have mediocre names and non-obvious semantics, so aren't /// currently on a path to potential stabilization. -#[cfg(not(bootstrap))] impl<R: ops::TryV2> ControlFlow<R, R::Output> { /// Create a `ControlFlow` from any type implementing `Try`. #[inline] diff --git a/library/core/src/ops/drop.rs b/library/core/src/ops/drop.rs index f4b1ec377d4..aa654aa5570 100644 --- a/library/core/src/ops/drop.rs +++ b/library/core/src/ops/drop.rs @@ -11,7 +11,7 @@ /// This destructor consists of two components: /// - A call to `Drop::drop` for that value, if this special `Drop` trait is implemented for its type. /// - The automatically generated "drop glue" which recursively calls the destructors -/// of the all fields of this value. +/// of all the fields of this value. /// /// As Rust automatically calls the destructors of all contained fields, /// you don't have to implement `Drop` in most cases. But there are some cases where diff --git a/library/core/src/ops/mod.rs b/library/core/src/ops/mod.rs index 139a8c0eec9..85e04740d96 100644 --- a/library/core/src/ops/mod.rs +++ b/library/core/src/ops/mod.rs @@ -147,8 +147,6 @@ mod function; mod generator; mod index; mod range; -#[cfg(bootstrap)] -mod r#try; mod try_trait; mod unsize; @@ -183,19 +181,10 @@ pub use self::range::{Range, RangeFrom, RangeFull, RangeTo}; #[stable(feature = "inclusive_range", since = "1.26.0")] pub use self::range::{Bound, RangeBounds, RangeInclusive, RangeToInclusive}; -#[unstable(feature = "try_trait", issue = "42327")] -#[cfg(bootstrap)] -pub use self::r#try::Try; - -#[unstable(feature = "try_trait_transition", reason = "for bootstrap", issue = "none")] -#[cfg(bootstrap)] -pub(crate) use self::r#try::Try as TryV1; - #[unstable(feature = "try_trait_v2", issue = "84277")] pub use self::try_trait::FromResidual; #[unstable(feature = "try_trait_v2", issue = "84277")] -#[cfg(not(bootstrap))] pub use self::try_trait::Try; #[unstable(feature = "try_trait_transition", reason = "for bootstrap", issue = "none")] diff --git a/library/core/src/ops/range.rs b/library/core/src/ops/range.rs index 684e6bb4a0f..347a346359f 100644 --- a/library/core/src/ops/range.rs +++ b/library/core/src/ops/range.rs @@ -686,7 +686,7 @@ impl<T> Bound<T> { } } - /// Converts from `&mut Bound<T>` to `Bound<&T>`. + /// Converts from `&mut Bound<T>` to `Bound<&mut T>`. #[inline] #[unstable(feature = "bound_as_ref", issue = "80996")] pub fn as_mut(&mut self) -> Bound<&mut T> { @@ -737,14 +737,13 @@ impl<T: Clone> Bound<&T> { /// # Examples /// /// ``` - /// #![feature(bound_cloned)] /// use std::ops::Bound::*; /// use std::ops::RangeBounds; /// /// assert_eq!((1..12).start_bound(), Included(&1)); /// assert_eq!((1..12).start_bound().cloned(), Included(1)); /// ``` - #[unstable(feature = "bound_cloned", issue = "61356")] + #[stable(feature = "bound_cloned", since = "1.55.0")] pub fn cloned(self) -> Bound<T> { match self { Bound::Unbounded => Bound::Unbounded, @@ -813,12 +812,12 @@ pub trait RangeBounds<T: ?Sized> { U: ?Sized + PartialOrd<T>, { (match self.start_bound() { - Included(ref start) => *start <= item, - Excluded(ref start) => *start < item, + Included(start) => start <= item, + Excluded(start) => start < item, Unbounded => true, }) && (match self.end_bound() { - Included(ref end) => item <= *end, - Excluded(ref end) => item < *end, + Included(end) => item <= end, + Excluded(end) => item < end, Unbounded => true, }) } diff --git a/library/core/src/ops/try.rs b/library/core/src/ops/try.rs deleted file mode 100644 index 9d659e78d3c..00000000000 --- a/library/core/src/ops/try.rs +++ /dev/null @@ -1,61 +0,0 @@ -/// A trait for customizing the behavior of the `?` operator. -/// -/// A type implementing `Try` is one that has a canonical way to view it -/// in terms of a success/failure dichotomy. This trait allows both -/// extracting those success or failure values from an existing instance and -/// creating a new instance from a success or failure value. -#[unstable(feature = "try_trait", issue = "42327")] -#[rustc_on_unimplemented( - on( - all( - any(from_method = "from_error", from_method = "from_ok"), - from_desugaring = "QuestionMark" - ), - message = "the `?` operator can only be used in {ItemContext} \ - that returns `Result` or `Option` \ - (or another type that implements `{Try}`)", - label = "cannot use the `?` operator in {ItemContext} that returns `{Self}`", - enclosing_scope = "this function should return `Result` or `Option` to accept `?`" - ), - on( - all(from_method = "into_result", from_desugaring = "QuestionMark"), - message = "the `?` operator can only be applied to values \ - that implement `{Try}`", - label = "the `?` operator cannot be applied to type `{Self}`" - ) -)] -#[doc(alias = "?")] -#[cfg_attr(bootstrap, lang = "try")] -pub trait Try { - /// The type of this value when viewed as successful. - #[unstable(feature = "try_trait", issue = "42327")] - type Output; // This no longer follows its RFC, but is only used in bootstrap. - /// The type of this value when viewed as failed. - #[unstable(feature = "try_trait", issue = "42327")] - type Error; - - /// Applies the "?" operator. A return of `Ok(t)` means that the - /// execution should continue normally, and the result of `?` is the - /// value `t`. A return of `Err(e)` means that execution should branch - /// to the innermost enclosing `catch`, or return from the function. - /// - /// If an `Err(e)` result is returned, the value `e` will be "wrapped" - /// in the return type of the enclosing scope (which must itself implement - /// `Try`). Specifically, the value `X::from_error(From::from(e))` - /// is returned, where `X` is the return type of the enclosing function. - #[cfg_attr(bootstrap, lang = "into_result")] - #[unstable(feature = "try_trait", issue = "42327")] - fn into_result(self) -> Result<Self::Output, Self::Error>; - - /// Wrap an error value to construct the composite result. For example, - /// `Result::Err(x)` and `Result::from_error(x)` are equivalent. - #[cfg_attr(bootstrap, lang = "from_error")] - #[unstable(feature = "try_trait", issue = "42327")] - fn from_error(v: Self::Error) -> Self; - - /// Wrap an OK value to construct the composite result. For example, - /// `Result::Ok(x)` and `Result::from_ok(x)` are equivalent. - #[cfg_attr(bootstrap, lang = "from_ok")] - #[unstable(feature = "try_trait", issue = "42327")] - fn from_ok(v: Self::Output) -> Self; -} diff --git a/library/core/src/ops/try_trait.rs b/library/core/src/ops/try_trait.rs index 1d9bc452618..6bdcda775ee 100644 --- a/library/core/src/ops/try_trait.rs +++ b/library/core/src/ops/try_trait.rs @@ -55,7 +55,6 @@ use crate::ops::ControlFlow; /// into the return type using [`Try::from_output`]: /// ``` /// # #![feature(try_trait_v2)] -/// # #![feature(control_flow_enum)] /// # use std::ops::{ControlFlow, Try}; /// fn simple_try_fold_2<A, T, R: Try<Output = A>>( /// iter: impl Iterator<Item = T>, @@ -79,7 +78,6 @@ use crate::ops::ControlFlow; /// recreated from their corresponding residual, so we'll just call it: /// ``` /// # #![feature(try_trait_v2)] -/// # #![feature(control_flow_enum)] /// # use std::ops::{ControlFlow, Try}; /// pub fn simple_try_fold_3<A, T, R: Try<Output = A>>( /// iter: impl Iterator<Item = T>, @@ -130,7 +128,7 @@ use crate::ops::ControlFlow; ) )] #[doc(alias = "?")] -#[cfg_attr(not(bootstrap), lang = "Try")] +#[lang = "Try"] pub trait Try: FromResidual { /// The type of the value produced by `?` when *not* short-circuiting. #[unstable(feature = "try_trait_v2", issue = "84277")] @@ -170,7 +168,6 @@ pub trait Try: FromResidual { /// /// ``` /// #![feature(try_trait_v2)] - /// #![feature(control_flow_enum)] /// use std::ops::Try; /// /// assert_eq!(<Result<_, String> as Try>::from_output(3), Ok(3)); @@ -189,7 +186,7 @@ pub trait Try: FromResidual { /// let r = std::iter::empty().try_fold(4, |_, ()| -> Option<_> { unreachable!() }); /// assert_eq!(r, Some(4)); /// ``` - #[cfg_attr(not(bootstrap), lang = "from_output")] + #[lang = "from_output"] #[unstable(feature = "try_trait_v2", issue = "84277")] fn from_output(output: Self::Output) -> Self; @@ -202,7 +199,6 @@ pub trait Try: FromResidual { /// /// ``` /// #![feature(try_trait_v2)] - /// #![feature(control_flow_enum)] /// use std::ops::{ControlFlow, Try}; /// /// assert_eq!(Ok::<_, String>(3).branch(), ControlFlow::Continue(3)); @@ -217,7 +213,7 @@ pub trait Try: FromResidual { /// ControlFlow::Break(ControlFlow::Break(3)), /// ); /// ``` - #[cfg_attr(not(bootstrap), lang = "branch")] + #[lang = "branch"] #[unstable(feature = "try_trait_v2", issue = "84277")] fn branch(self) -> ControlFlow<Self::Residual, Self::Output>; } @@ -323,13 +319,12 @@ pub trait FromResidual<R = <Self as Try>::Residual> { /// This should be implemented consistently with the `branch` method such /// that applying the `?` operator will get back an equivalent residual: /// `FromResidual::from_residual(r).branch() --> ControlFlow::Break(r)`. - /// (It may not be an *identical* residual when interconversion is involved.) + /// (It must not be an *identical* residual when interconversion is involved.) /// /// # Examples /// /// ``` /// #![feature(try_trait_v2)] - /// #![feature(control_flow_enum)] /// use std::ops::{ControlFlow, FromResidual}; /// /// assert_eq!(Result::<String, i64>::from_residual(Err(3_u8)), Err(3)); @@ -339,7 +334,7 @@ pub trait FromResidual<R = <Self as Try>::Residual> { /// ControlFlow::Break(5), /// ); /// ``` - #[cfg_attr(not(bootstrap), lang = "from_residual")] + #[lang = "from_residual"] #[unstable(feature = "try_trait_v2", issue = "84277")] fn from_residual(residual: R) -> Self; } diff --git a/library/core/src/option.rs b/library/core/src/option.rs index 4e7afca6a49..78f5954532f 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -49,9 +49,11 @@ //! no "null" references. Instead, Rust has *optional* pointers, like //! the optional owned box, [`Option`]`<`[`Box<T>`]`>`. //! +//! [`Box<T>`]: ../../std/boxed/struct.Box.html +//! //! The following example uses [`Option`] to create an optional box of -//! [`i32`]. Notice that in order to use the inner [`i32`] value first, the -//! `check_optional` function needs to use pattern matching to +//! [`i32`]. Notice that in order to use the inner [`i32`] value, the +//! `check_optional` function first needs to use pattern matching to //! determine whether the box has a value (i.e., it is [`Some(...)`][`Some`]) or //! not ([`None`]). //! @@ -83,6 +85,10 @@ //! * [`ptr::NonNull<U>`] //! * `#[repr(transparent)]` struct around one of the types in this list. //! +//! [`Box<U>`]: ../../std/boxed/struct.Box.html +//! [`num::NonZero*`]: crate::num +//! [`ptr::NonNull<U>`]: crate::ptr::NonNull +//! //! This is called the "null pointer optimization" or NPO. //! //! It is further guaranteed that, for the cases above, one can @@ -90,6 +96,352 @@ //! from `Some::<T>(_)` to `T` (but transmuting `None::<T>` to `T` //! is undefined behaviour). //! +//! # Method overview +//! +//! In addition to working with pattern matching, [`Option`] provides a wide +//! variety of different methods. +//! +//! ## Querying the variant +//! +//! The [`is_some`] and [`is_none`] methods return [`true`] if the [`Option`] +//! is [`Some`] or [`None`], respectively. +//! +//! [`is_none`]: Option::is_none +//! [`is_some`]: Option::is_some +//! +//! ## Adapters for working with references +//! +//! * [`as_ref`] converts from `&Option<T>` to `Option<&T>` +//! * [`as_mut`] converts from `&mut Option<T>` to `Option<&mut T>` +//! * [`as_deref`] converts from `&Option<T>` to `Option<&T::Target>` +//! * [`as_deref_mut`] converts from `&mut Option<T>` to +//! `Option<&mut T::Target>` +//! * [`as_pin_ref`] converts from [`Pin`]`<&Option<T>>` to +//! `Option<`[`Pin`]`<&T>>` +//! * [`as_pin_mut`] converts from [`Pin`]`<&mut Option<T>>` to +//! `Option<`[`Pin`]`<&mut T>>` +//! +//! [`as_deref`]: Option::as_deref +//! [`as_deref_mut`]: Option::as_deref_mut +//! [`as_mut`]: Option::as_mut +//! [`as_pin_mut`]: Option::as_pin_mut +//! [`as_pin_ref`]: Option::as_pin_ref +//! [`as_ref`]: Option::as_ref +//! +//! ## Extracting the contained value +//! +//! These methods extract the contained value in an [`Option<T>`] when it +//! is the [`Some`] variant. If the [`Option`] is [`None`]: +//! +//! * [`expect`] panics with a provided custom message +//! * [`unwrap`] panics with a generic message +//! * [`unwrap_or`] returns the provided default value +//! * [`unwrap_or_default`] returns the default value of the type `T` +//! (which must implement the [`Default`] trait) +//! * [`unwrap_or_else`] returns the result of evaluating the provided +//! function +//! +//! [`expect`]: Option::expect +//! [`unwrap`]: Option::unwrap +//! [`unwrap_or`]: Option::unwrap_or +//! [`unwrap_or_default`]: Option::unwrap_or_default +//! [`unwrap_or_else`]: Option::unwrap_or_else +//! +//! ## Transforming contained values +//! +//! These methods transform [`Option`] to [`Result`]: +//! +//! * [`ok_or`] transforms [`Some(v)`] to [`Ok(v)`], and [`None`] to +//! [`Err(err)`] using the provided default `err` value +//! * [`ok_or_else`] transforms [`Some(v)`] to [`Ok(v)`], and [`None`] to +//! a value of [`Err`] using the provided function +//! * [`transpose`] transposes an [`Option`] of a [`Result`] into a +//! [`Result`] of an [`Option`] +//! +//! [`Err(err)`]: Err +//! [`Ok(v)`]: Ok +//! [`Some(v)`]: Some +//! [`ok_or`]: Option::ok_or +//! [`ok_or_else`]: Option::ok_or_else +//! [`transpose`]: Option::transpose +//! +//! These methods transform the [`Some`] variant: +//! +//! * [`filter`] calls the provided predicate function on the contained +//! value `t` if the [`Option`] is [`Some(t)`], and returns [`Some(t)`] +//! if the function returns `true`; otherwise, returns [`None`] +//! * [`flatten`] removes one level of nesting from an +//! [`Option<Option<T>>`] +//! * [`map`] transforms [`Option<T>`] to [`Option<U>`] by applying the +//! provided function to the contained value of [`Some`] and leaving +//! [`None`] values unchanged +//! +//! [`Some(t)`]: Some +//! [`filter`]: Option::filter +//! [`flatten`]: Option::flatten +//! [`map`]: Option::map +//! +//! These methods transform [`Option<T>`] to a value of a possibly +//! different type `U`: +//! +//! * [`map_or`] applies the provided function to the contained value of +//! [`Some`], or returns the provided default value if the [`Option`] is +//! [`None`] +//! * [`map_or_else`] applies the provided function to the contained value +//! of [`Some`], or returns the result of evaluating the provided +//! fallback function if the [`Option`] is [`None`] +//! +//! [`map_or`]: Option::map_or +//! [`map_or_else`]: Option::map_or_else +//! +//! These methods combine the [`Some`] variants of two [`Option`] values: +//! +//! * [`zip`] returns [`Some((s, o))`] if `self` is [`Some(s)`] and the +//! provided [`Option`] value is [`Some(o)`]; otherwise, returns [`None`] +//! * [`zip_with`] calls the provided function `f` and returns +//! [`Some(f(s, o))`] if `self` is [`Some(s)`] and the provided +//! [`Option`] value is [`Some(o)`]; otherwise, returns [`None`] +//! +//! [`Some(f(s, o))`]: Some +//! [`Some(o)`]: Some +//! [`Some(s)`]: Some +//! [`Some((s, o))`]: Some +//! [`zip`]: Option::zip +//! [`zip_with`]: Option::zip_with +//! +//! ## Boolean operators +//! +//! These methods treat the [`Option`] as a boolean value, where [`Some`] +//! acts like [`true`] and [`None`] acts like [`false`]. There are two +//! categories of these methods: ones that take an [`Option`] as input, and +//! ones that take a function as input (to be lazily evaluated). +//! +//! The [`and`], [`or`], and [`xor`] methods take another [`Option`] as +//! input, and produce an [`Option`] as output. Only the [`and`] method can +//! produce an [`Option<U>`] value having a different inner type `U` than +//! [`Option<T>`]. +//! +//! | method | self | input | output | +//! |---------|-----------|-----------|-----------| +//! | [`and`] | `None` | (ignored) | `None` | +//! | [`and`] | `Some(x)` | `None` | `None` | +//! | [`and`] | `Some(x)` | `Some(y)` | `Some(y)` | +//! | [`or`] | `None` | `None` | `None` | +//! | [`or`] | `None` | `Some(y)` | `Some(y)` | +//! | [`or`] | `Some(x)` | (ignored) | `Some(x)` | +//! | [`xor`] | `None` | `None` | `None` | +//! | [`xor`] | `None` | `Some(y)` | `Some(y)` | +//! | [`xor`] | `Some(x)` | `None` | `Some(x)` | +//! | [`xor`] | `Some(x)` | `Some(y)` | `None` | +//! +//! [`and`]: Option::and +//! [`or`]: Option::or +//! [`xor`]: Option::xor +//! +//! The [`and_then`] and [`or_else`] methods take a function as input, and +//! only evaluate the function when they need to produce a new value. Only +//! the [`and_then`] method can produce an [`Option<U>`] value having a +//! different inner type `U` than [`Option<T>`]. +//! +//! | method | self | function input | function result | output | +//! |--------------|-----------|----------------|-----------------|-----------| +//! | [`and_then`] | `None` | (not provided) | (not evaluated) | `None` | +//! | [`and_then`] | `Some(x)` | `x` | `None` | `None` | +//! | [`and_then`] | `Some(x)` | `x` | `Some(y)` | `Some(y)` | +//! | [`or_else`] | `None` | (not provided) | `None` | `None` | +//! | [`or_else`] | `None` | (not provided) | `Some(y)` | `Some(y)` | +//! | [`or_else`] | `Some(x)` | (not provided) | (not evaluated) | `Some(x)` | +//! +//! [`and_then`]: Option::and_then +//! [`or_else`]: Option::or_else +//! +//! This is an example of using methods like [`and_then`] and [`or`] in a +//! pipeline of method calls. Early stages of the pipeline pass failure +//! values ([`None`]) through unchanged, and continue processing on +//! success values ([`Some`]). Toward the end, [`or`] substitutes an error +//! message if it receives [`None`]. +//! +//! ``` +//! # use std::collections::BTreeMap; +//! let mut bt = BTreeMap::new(); +//! bt.insert(20u8, "foo"); +//! bt.insert(42u8, "bar"); +//! let res = vec![0u8, 1, 11, 200, 22] +//! .into_iter() +//! .map(|x| { +//! // `checked_sub()` returns `None` on error +//! x.checked_sub(1) +//! // same with `checked_mul()` +//! .and_then(|x| x.checked_mul(2)) +//! // `BTreeMap::get` returns `None` on error +//! .and_then(|x| bt.get(&x)) +//! // Substitute an error message if we have `None` so far +//! .or(Some(&"error!")) +//! .copied() +//! // Won't panic because we unconditionally used `Some` above +//! .unwrap() +//! }) +//! .collect::<Vec<_>>(); +//! assert_eq!(res, ["error!", "error!", "foo", "error!", "bar"]); +//! ``` +//! +//! ## Comparison operators +//! +//! If `T` implements [`PartialOrd`] then [`Option<T>`] will derive its +//! [`PartialOrd`] implementation. With this order, [`None`] compares as +//! less than any [`Some`], and two [`Some`] compare the same way as their +//! contained values would in `T`. If `T` also implements +//! [`Ord`], then so does [`Option<T>`]. +//! +//! ``` +//! assert!(None < Some(0)); +//! assert!(Some(0) < Some(1)); +//! ``` +//! +//! ## Iterating over `Option` +//! +//! An [`Option`] can be iterated over. This can be helpful if you need an +//! iterator that is conditionally empty. The iterator will either produce +//! a single value (when the [`Option`] is [`Some`]), or produce no values +//! (when the [`Option`] is [`None`]). For example, [`into_iter`] acts like +//! [`once(v)`] if the [`Option`] is [`Some(v)`], and like [`empty()`] if +//! the [`Option`] is [`None`]. +//! +//! [`Some(v)`]: Some +//! [`empty()`]: crate::iter::empty +//! [`once(v)`]: crate::iter::once +//! +//! Iterators over [`Option<T>`] come in three types: +//! +//! * [`into_iter`] consumes the [`Option`] and produces the contained +//! value +//! * [`iter`] produces an immutable reference of type `&T` to the +//! contained value +//! * [`iter_mut`] produces a mutable reference of type `&mut T` to the +//! contained value +//! +//! [`into_iter`]: Option::into_iter +//! [`iter`]: Option::iter +//! [`iter_mut`]: Option::iter_mut +//! +//! An iterator over [`Option`] can be useful when chaining iterators, for +//! example, to conditionally insert items. (It's not always necessary to +//! explicitly call an iterator constructor: many [`Iterator`] methods that +//! accept other iterators will also accept iterable types that implement +//! [`IntoIterator`], which includes [`Option`].) +//! +//! ``` +//! let yep = Some(42); +//! let nope = None; +//! // chain() already calls into_iter(), so we don't have to do so +//! let nums: Vec<i32> = (0..4).chain(yep).chain(4..8).collect(); +//! assert_eq!(nums, [0, 1, 2, 3, 42, 4, 5, 6, 7]); +//! let nums: Vec<i32> = (0..4).chain(nope).chain(4..8).collect(); +//! assert_eq!(nums, [0, 1, 2, 3, 4, 5, 6, 7]); +//! ``` +//! +//! One reason to chain iterators in this way is that a function returning +//! `impl Iterator` must have all possible return values be of the same +//! concrete type. Chaining an iterated [`Option`] can help with that. +//! +//! ``` +//! fn make_iter(do_insert: bool) -> impl Iterator<Item = i32> { +//! // Explicit returns to illustrate return types matching +//! match do_insert { +//! true => return (0..4).chain(Some(42)).chain(4..8), +//! false => return (0..4).chain(None).chain(4..8), +//! } +//! } +//! println!("{:?}", make_iter(true).collect::<Vec<_>>()); +//! println!("{:?}", make_iter(false).collect::<Vec<_>>()); +//! ``` +//! +//! If we try to do the same thing, but using [`once()`] and [`empty()`], +//! we can't return `impl Iterator` anymore because the concrete types of +//! the return values differ. +//! +//! [`empty()`]: crate::iter::empty +//! [`once()`]: crate::iter::once +//! +//! ```compile_fail,E0308 +//! # use std::iter::{empty, once}; +//! // This won't compile because all possible returns from the function +//! // must have the same concrete type. +//! fn make_iter(do_insert: bool) -> impl Iterator<Item = i32> { +//! // Explicit returns to illustrate return types not matching +//! match do_insert { +//! true => return (0..4).chain(once(42)).chain(4..8), +//! false => return (0..4).chain(empty()).chain(4..8), +//! } +//! } +//! ``` +//! +//! ## Collecting into `Option` +//! +//! [`Option`] implements the [`FromIterator`][impl-FromIterator] trait, +//! which allows an iterator over [`Option`] values to be collected into an +//! [`Option`] of a collection of each contained value of the original +//! [`Option`] values, or [`None`] if any of the elements was [`None`]. +//! +//! [impl-FromIterator]: Option#impl-FromIterator%3COption%3CA%3E%3E +//! +//! ``` +//! let v = vec![Some(2), Some(4), None, Some(8)]; +//! let res: Option<Vec<_>> = v.into_iter().collect(); +//! assert_eq!(res, None); +//! let v = vec![Some(2), Some(4), Some(8)]; +//! let res: Option<Vec<_>> = v.into_iter().collect(); +//! assert_eq!(res, Some(vec![2, 4, 8])); +//! ``` +//! +//! [`Option`] also implements the [`Product`][impl-Product] and +//! [`Sum`][impl-Sum] traits, allowing an iterator over [`Option`] values +//! to provide the [`product`][Iterator::product] and +//! [`sum`][Iterator::sum] methods. +//! +//! [impl-Product]: Option#impl-Product%3COption%3CU%3E%3E +//! [impl-Sum]: Option#impl-Sum%3COption%3CU%3E%3E +//! +//! ``` +//! let v = vec![None, Some(1), Some(2), Some(3)]; +//! let res: Option<i32> = v.into_iter().sum(); +//! assert_eq!(res, None); +//! let v = vec![Some(1), Some(2), Some(21)]; +//! let res: Option<i32> = v.into_iter().product(); +//! assert_eq!(res, Some(42)); +//! ``` +//! +//! ## Modifying an [`Option`] in-place +//! +//! These methods return a mutable reference to the contained value of an +//! [`Option<T>`]: +//! +//! * [`insert`] inserts a value, dropping any old contents +//! * [`get_or_insert`] gets the current value, inserting a provided +//! default value if it is [`None`] +//! * [`get_or_insert_default`] gets the current value, inserting the +//! default value of type `T` (which must implement [`Default`]) if it is +//! [`None`] +//! * [`get_or_insert_with`] gets the current value, inserting a default +//! computed by the provided function if it is [`None`] +//! +//! [`get_or_insert`]: Option::get_or_insert +//! [`get_or_insert_default`]: Option::get_or_insert_default +//! [`get_or_insert_with`]: Option::get_or_insert_with +//! [`insert`]: Option::insert +//! +//! These methods transfer ownership of the contained value of an +//! [`Option`]: +//! +//! * [`take`] takes ownership of the contained value of an [`Option`], if +//! any, replacing the [`Option`] with [`None`] +//! * [`replace`] takes ownership of the contained value of an [`Option`], +//! if any, replacing the [`Option`] with a [`Some`] containing the +//! provided value +//! +//! [`replace`]: Option::replace +//! [`take`]: Option::take +//! //! # Examples //! //! Basic pattern matching on [`Option`]: @@ -141,11 +493,6 @@ //! None => println!("there are no animals :("), //! } //! ``` -//! -//! [`Box<T>`]: ../../std/boxed/struct.Box.html -//! [`Box<U>`]: ../../std/boxed/struct.Box.html -//! [`num::NonZero*`]: crate::num -//! [`ptr::NonNull<U>`]: crate::ptr::NonNull #![stable(feature = "rust1", since = "1.0.0")] @@ -845,6 +1192,7 @@ impl<T> Option<T> { /// *val = 3; /// assert_eq!(opt.unwrap(), 3); /// ``` + #[must_use = "if you intended to set a value, consider assignment instead"] #[inline] #[stable(feature = "option_insert", since = "1.53.0")] pub fn insert(&mut self, value: T) -> &mut T { @@ -1051,6 +1399,33 @@ impl<T> Option<T> { } } +impl<T, U> Option<(T, U)> { + /// Unzips an option containing a tuple of two options + /// + /// If `self` is `Some((a, b))` this method returns `(Some(a), Some(b))`. + /// Otherwise, `(None, None)` is returned. + /// + /// # Examples + /// + /// ``` + /// #![feature(unzip_option)] + /// + /// let x = Some((1, "hi")); + /// let y = None::<(u8, u32)>; + /// + /// assert_eq!(x.unzip(), (Some(1), Some("hi"))); + /// assert_eq!(y.unzip(), (None, None)); + /// ``` + #[inline] + #[unstable(feature = "unzip_option", issue = "87800", reason = "recently added")] + pub const fn unzip(self) -> (Option<T>, Option<U>) { + match self { + Some((a, b)) => (Some(a), Some(b)), + None => (None, None), + } + } +} + impl<T: Copy> Option<&T> { /// Maps an `Option<&T>` to an `Option<T>` by copying the contents of the /// option. @@ -1267,7 +1642,8 @@ impl<T: Clone> Clone for Option<T> { } #[stable(feature = "rust1", since = "1.0.0")] -impl<T> Default for Option<T> { +#[rustc_const_unstable(feature = "const_default_impls", issue = "87864")] +impl<T> const Default for Option<T> { /// Returns [`None`][Option::None]. /// /// # Examples @@ -1350,7 +1726,7 @@ impl<'a, T> From<&'a Option<T>> for Option<&'a T> { /// /// Converts an `Option<`[`String`]`>` into an `Option<`[`usize`]`>`, preserving the original. /// The [`map`] method takes the `self` argument by value, consuming the original, - /// so this technique uses `as_ref` to first take an `Option` to a reference + /// so this technique uses `from` to first take an `Option` to a reference /// to the value inside the original. /// /// [`map`]: Option::map @@ -1636,38 +2012,6 @@ impl<A, V: FromIterator<A>> FromIterator<Option<A>> for Option<V> { } } -/// The error type that results from applying the try operator (`?`) to a `None` value. If you wish -/// to allow `x?` (where `x` is an `Option<T>`) to be converted into your error type, you can -/// implement `impl From<NoneError>` for `YourErrorType`. In that case, `x?` within a function that -/// returns `Result<_, YourErrorType>` will translate a `None` value into an `Err` result. -#[rustc_diagnostic_item = "none_error"] -#[unstable(feature = "try_trait", issue = "42327")] -#[derive(Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Debug, Hash)] -#[cfg(bootstrap)] -pub struct NoneError; - -#[unstable(feature = "try_trait", issue = "42327")] -#[cfg(bootstrap)] -impl<T> ops::TryV1 for Option<T> { - type Output = T; - type Error = NoneError; - - #[inline] - fn into_result(self) -> Result<T, NoneError> { - self.ok_or(NoneError) - } - - #[inline] - fn from_ok(v: T) -> Self { - Some(v) - } - - #[inline] - fn from_error(_: NoneError) -> Self { - None - } -} - #[unstable(feature = "try_trait_v2", issue = "84277")] impl<T> ops::TryV2 for Option<T> { type Output = T; diff --git a/library/core/src/panic.rs b/library/core/src/panic.rs index cbb10c324c4..463bec37265 100644 --- a/library/core/src/panic.rs +++ b/library/core/src/panic.rs @@ -2,12 +2,22 @@ #![stable(feature = "core_panic_info", since = "1.41.0")] +mod location; +mod panic_info; +mod unwind_safe; + use crate::any::Any; -use crate::fmt; + +#[stable(feature = "panic_hooks", since = "1.10.0")] +pub use self::location::Location; +#[stable(feature = "panic_hooks", since = "1.10.0")] +pub use self::panic_info::PanicInfo; +#[stable(feature = "catch_unwind", since = "1.9.0")] +pub use self::unwind_safe::{AssertUnwindSafe, RefUnwindSafe, UnwindSafe}; #[doc(hidden)] #[unstable(feature = "edition_panic", issue = "none", reason = "use panic!() instead")] -#[allow_internal_unstable(core_panic)] +#[allow_internal_unstable(core_panic, const_format_args)] #[rustc_diagnostic_item = "core_panic_2015_macro"] #[rustc_macro_transparency = "semitransparent"] pub macro panic_2015 { @@ -21,13 +31,13 @@ pub macro panic_2015 { $crate::panicking::panic_str($msg) ), ($fmt:expr, $($arg:tt)+) => ( - $crate::panicking::panic_fmt($crate::format_args!($fmt, $($arg)+)) + $crate::panicking::panic_fmt($crate::const_format_args!($fmt, $($arg)+)) ), } #[doc(hidden)] #[unstable(feature = "edition_panic", issue = "none", reason = "use panic!() instead")] -#[allow_internal_unstable(core_panic)] +#[allow_internal_unstable(core_panic, const_format_args)] #[rustc_diagnostic_item = "core_panic_2021_macro"] #[rustc_macro_transparency = "semitransparent"] pub macro panic_2021 { @@ -35,338 +45,10 @@ pub macro panic_2021 { $crate::panicking::panic("explicit panic") ), ($($t:tt)+) => ( - $crate::panicking::panic_fmt($crate::format_args!($($t)+)) + $crate::panicking::panic_fmt($crate::const_format_args!($($t)+)) ), } -/// A struct providing information about a panic. -/// -/// `PanicInfo` structure is passed to a panic hook set by the [`set_hook`] -/// function. -/// -/// [`set_hook`]: ../../std/panic/fn.set_hook.html -/// -/// # 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 { -/// println!("panic occurred"); -/// } -/// })); -/// -/// panic!("Normal panic"); -/// ``` -#[lang = "panic_info"] -#[stable(feature = "panic_hooks", since = "1.10.0")] -#[derive(Debug)] -pub struct PanicInfo<'a> { - payload: &'a (dyn Any + Send), - message: Option<&'a fmt::Arguments<'a>>, - location: &'a Location<'a>, -} - -impl<'a> PanicInfo<'a> { - #[unstable( - feature = "panic_internals", - reason = "internal details of the implementation of the `panic!` and related macros", - issue = "none" - )] - #[doc(hidden)] - #[inline] - pub fn internal_constructor( - message: Option<&'a fmt::Arguments<'a>>, - location: &'a Location<'a>, - ) -> Self { - struct NoPayload; - PanicInfo { location, message, payload: &NoPayload } - } - - #[unstable( - feature = "panic_internals", - reason = "internal details of the implementation of the `panic!` and related macros", - issue = "none" - )] - #[doc(hidden)] - #[inline] - pub fn set_payload(&mut self, info: &'a (dyn Any + Send)) { - self.payload = info; - } - - /// Returns the payload associated with the panic. - /// - /// This will commonly, but not always, be a `&'static str` or [`String`]. - /// - /// [`String`]: ../../std/string/struct.String.html - /// - /// # 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 { - /// println!("panic occurred"); - /// } - /// })); - /// - /// panic!("Normal panic"); - /// ``` - #[stable(feature = "panic_hooks", since = "1.10.0")] - pub fn payload(&self) -> &(dyn Any + Send) { - self.payload - } - - /// If the `panic!` macro from the `core` crate (not from `std`) - /// was used with a formatting string and some additional arguments, - /// returns that message ready to be used for example with [`fmt::write`] - #[unstable(feature = "panic_info_message", issue = "66745")] - pub fn message(&self) -> Option<&fmt::Arguments<'_>> { - self.message - } - - /// 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"); - /// ``` - #[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 std::panicking::begin_panic_fmt. - Some(&self.location) - } -} - -#[stable(feature = "panic_hook_display", since = "1.26.0")] -impl fmt::Display for PanicInfo<'_> { - fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { - formatter.write_str("panicked at ")?; - if let Some(message) = self.message { - write!(formatter, "'{}', ", message)? - } else if let Some(payload) = self.payload.downcast_ref::<&'static str>() { - write!(formatter, "'{}', ", payload)? - } - // NOTE: we cannot use downcast_ref::<String>() here - // since String is not available in libcore! - // The payload is a String when `std::panic!` is called with multiple arguments, - // but in that case the message is also available. - - self.location.fmt(formatter) - } -} - -/// A struct containing information about the location of a panic. -/// -/// This structure is created by [`PanicInfo::location()`]. -/// -/// # 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"); -/// ``` -/// -/// # Comparisons -/// -/// Comparisons for equality and ordering are made in file, line, then column priority. -/// Files are compared as strings, not `Path`, which could be unexpected. -/// See [`Location::file`]'s documentation for more discussion. -#[lang = "panic_location"] -#[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] -#[stable(feature = "panic_hooks", since = "1.10.0")] -pub struct Location<'a> { - file: &'a str, - line: u32, - col: u32, -} - -impl<'a> Location<'a> { - /// Returns the source location of the caller of this function. If that function's caller is - /// annotated then its call location will be returned, and so on up the stack to the first call - /// within a non-tracked function body. - /// - /// # Examples - /// - /// ``` - /// use std::panic::Location; - /// - /// /// Returns the [`Location`] at which it is called. - /// #[track_caller] - /// fn get_caller_location() -> &'static Location<'static> { - /// Location::caller() - /// } - /// - /// /// Returns a [`Location`] from within this function's definition. - /// fn get_just_one_location() -> &'static Location<'static> { - /// get_caller_location() - /// } - /// - /// let fixed_location = get_just_one_location(); - /// assert_eq!(fixed_location.file(), file!()); - /// assert_eq!(fixed_location.line(), 14); - /// assert_eq!(fixed_location.column(), 5); - /// - /// // running the same untracked function in a different location gives us the same result - /// let second_fixed_location = get_just_one_location(); - /// assert_eq!(fixed_location.file(), second_fixed_location.file()); - /// assert_eq!(fixed_location.line(), second_fixed_location.line()); - /// assert_eq!(fixed_location.column(), second_fixed_location.column()); - /// - /// let this_location = get_caller_location(); - /// assert_eq!(this_location.file(), file!()); - /// assert_eq!(this_location.line(), 28); - /// assert_eq!(this_location.column(), 21); - /// - /// // running the tracked function in a different location produces a different value - /// let another_location = get_caller_location(); - /// assert_eq!(this_location.file(), another_location.file()); - /// assert_ne!(this_location.line(), another_location.line()); - /// assert_ne!(this_location.column(), another_location.column()); - /// ``` - #[stable(feature = "track_caller", since = "1.46.0")] - #[rustc_const_unstable(feature = "const_caller_location", issue = "76156")] - #[track_caller] - pub const fn caller() -> &'static Location<'static> { - crate::intrinsics::caller_location() - } -} - -impl<'a> Location<'a> { - #![unstable( - feature = "panic_internals", - reason = "internal details of the implementation of the `panic!` and related macros", - issue = "none" - )] - #[doc(hidden)] - pub const fn internal_constructor(file: &'a str, line: u32, col: u32) -> Self { - Location { file, line, col } - } - - /// Returns the name of the source file from which the panic originated. - /// - /// # `&str`, not `&Path` - /// - /// The returned name refers to a source path on the compiling system, but it isn't valid to - /// represent this directly as a `&Path`. The compiled code may run on a different system with - /// a different `Path` implementation than the system providing the contents and this library - /// does not currently have a different "host path" type. - /// - /// The most surprising behavior occurs when "the same" file is reachable via multiple paths in - /// the module system (usually using the `#[path = "..."]` attribute or similar), which can - /// cause what appears to be identical code to return differing values from this function. - /// - /// # Cross-compilation - /// - /// This value is not suitable for passing to `Path::new` or similar constructors when the host - /// platform and target platform differ. - /// - /// # 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 '{}'", location.file()); - /// } else { - /// println!("panic occurred but can't get location information..."); - /// } - /// })); - /// - /// panic!("Normal panic"); - /// ``` - #[stable(feature = "panic_hooks", since = "1.10.0")] - pub fn file(&self) -> &str { - self.file - } - - /// Returns the line number from which the panic originated. - /// - /// # Examples - /// - /// ```should_panic - /// use std::panic; - /// - /// panic::set_hook(Box::new(|panic_info| { - /// if let Some(location) = panic_info.location() { - /// println!("panic occurred at line {}", location.line()); - /// } else { - /// println!("panic occurred but can't get location information..."); - /// } - /// })); - /// - /// panic!("Normal panic"); - /// ``` - #[stable(feature = "panic_hooks", since = "1.10.0")] - pub fn line(&self) -> u32 { - self.line - } - - /// Returns the column from which the panic originated. - /// - /// # Examples - /// - /// ```should_panic - /// use std::panic; - /// - /// panic::set_hook(Box::new(|panic_info| { - /// if let Some(location) = panic_info.location() { - /// println!("panic occurred at column {}", location.column()); - /// } else { - /// println!("panic occurred but can't get location information..."); - /// } - /// })); - /// - /// panic!("Normal panic"); - /// ``` - #[stable(feature = "panic_col", since = "1.25.0")] - pub fn column(&self) -> u32 { - self.col - } -} - -#[stable(feature = "panic_hook_display", since = "1.26.0")] -impl fmt::Display for Location<'_> { - fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(formatter, "{}:{}:{}", self.file, self.line, self.col) - } -} - /// An internal trait used by libstd to pass data from libstd to `panic_unwind` /// and other panic runtimes. Not intended to be stabilized any time soon, do /// not use. diff --git a/library/core/src/panic/location.rs b/library/core/src/panic/location.rs new file mode 100644 index 00000000000..a482414caaf --- /dev/null +++ b/library/core/src/panic/location.rs @@ -0,0 +1,189 @@ +use crate::fmt; + +/// A struct containing information about the location of a panic. +/// +/// This structure is created by [`PanicInfo::location()`]. +/// +/// [`PanicInfo::location()`]: crate::panic::PanicInfo::location +/// +/// # 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"); +/// ``` +/// +/// # Comparisons +/// +/// Comparisons for equality and ordering are made in file, line, then column priority. +/// Files are compared as strings, not `Path`, which could be unexpected. +/// See [`Location::file`]'s documentation for more discussion. +#[lang = "panic_location"] +#[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] +#[stable(feature = "panic_hooks", since = "1.10.0")] +pub struct Location<'a> { + file: &'a str, + line: u32, + col: u32, +} + +impl<'a> Location<'a> { + /// Returns the source location of the caller of this function. If that function's caller is + /// annotated then its call location will be returned, and so on up the stack to the first call + /// within a non-tracked function body. + /// + /// # Examples + /// + /// ``` + /// use std::panic::Location; + /// + /// /// Returns the [`Location`] at which it is called. + /// #[track_caller] + /// fn get_caller_location() -> &'static Location<'static> { + /// Location::caller() + /// } + /// + /// /// Returns a [`Location`] from within this function's definition. + /// fn get_just_one_location() -> &'static Location<'static> { + /// get_caller_location() + /// } + /// + /// let fixed_location = get_just_one_location(); + /// assert_eq!(fixed_location.file(), file!()); + /// assert_eq!(fixed_location.line(), 14); + /// assert_eq!(fixed_location.column(), 5); + /// + /// // running the same untracked function in a different location gives us the same result + /// let second_fixed_location = get_just_one_location(); + /// assert_eq!(fixed_location.file(), second_fixed_location.file()); + /// assert_eq!(fixed_location.line(), second_fixed_location.line()); + /// assert_eq!(fixed_location.column(), second_fixed_location.column()); + /// + /// let this_location = get_caller_location(); + /// assert_eq!(this_location.file(), file!()); + /// assert_eq!(this_location.line(), 28); + /// assert_eq!(this_location.column(), 21); + /// + /// // running the tracked function in a different location produces a different value + /// let another_location = get_caller_location(); + /// assert_eq!(this_location.file(), another_location.file()); + /// assert_ne!(this_location.line(), another_location.line()); + /// assert_ne!(this_location.column(), another_location.column()); + /// ``` + #[stable(feature = "track_caller", since = "1.46.0")] + #[rustc_const_unstable(feature = "const_caller_location", issue = "76156")] + #[track_caller] + pub const fn caller() -> &'static Location<'static> { + crate::intrinsics::caller_location() + } + + /// Returns the name of the source file from which the panic originated. + /// + /// # `&str`, not `&Path` + /// + /// The returned name refers to a source path on the compiling system, but it isn't valid to + /// represent this directly as a `&Path`. The compiled code may run on a different system with + /// a different `Path` implementation than the system providing the contents and this library + /// does not currently have a different "host path" type. + /// + /// The most surprising behavior occurs when "the same" file is reachable via multiple paths in + /// the module system (usually using the `#[path = "..."]` attribute or similar), which can + /// cause what appears to be identical code to return differing values from this function. + /// + /// # Cross-compilation + /// + /// This value is not suitable for passing to `Path::new` or similar constructors when the host + /// platform and target platform differ. + /// + /// # 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 '{}'", location.file()); + /// } else { + /// println!("panic occurred but can't get location information..."); + /// } + /// })); + /// + /// panic!("Normal panic"); + /// ``` + #[stable(feature = "panic_hooks", since = "1.10.0")] + pub fn file(&self) -> &str { + self.file + } + + /// Returns the line number from which the panic originated. + /// + /// # Examples + /// + /// ```should_panic + /// use std::panic; + /// + /// panic::set_hook(Box::new(|panic_info| { + /// if let Some(location) = panic_info.location() { + /// println!("panic occurred at line {}", location.line()); + /// } else { + /// println!("panic occurred but can't get location information..."); + /// } + /// })); + /// + /// panic!("Normal panic"); + /// ``` + #[stable(feature = "panic_hooks", since = "1.10.0")] + pub fn line(&self) -> u32 { + self.line + } + + /// Returns the column from which the panic originated. + /// + /// # Examples + /// + /// ```should_panic + /// use std::panic; + /// + /// panic::set_hook(Box::new(|panic_info| { + /// if let Some(location) = panic_info.location() { + /// println!("panic occurred at column {}", location.column()); + /// } else { + /// println!("panic occurred but can't get location information..."); + /// } + /// })); + /// + /// panic!("Normal panic"); + /// ``` + #[stable(feature = "panic_col", since = "1.25.0")] + pub fn column(&self) -> u32 { + self.col + } +} + +#[unstable( + feature = "panic_internals", + reason = "internal details of the implementation of the `panic!` and related macros", + issue = "none" +)] +impl<'a> Location<'a> { + #[doc(hidden)] + pub const fn internal_constructor(file: &'a str, line: u32, col: u32) -> Self { + Location { file, line, col } + } +} + +#[stable(feature = "panic_hook_display", since = "1.26.0")] +impl fmt::Display for Location<'_> { + fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(formatter, "{}:{}:{}", self.file, self.line, self.col) + } +} diff --git a/library/core/src/panic/panic_info.rs b/library/core/src/panic/panic_info.rs new file mode 100644 index 00000000000..a52a0022e5d --- /dev/null +++ b/library/core/src/panic/panic_info.rs @@ -0,0 +1,145 @@ +use crate::any::Any; +use crate::fmt; +use crate::panic::Location; + +/// A struct providing information about a panic. +/// +/// `PanicInfo` structure is passed to a panic hook set by the [`set_hook`] +/// function. +/// +/// [`set_hook`]: ../../std/panic/fn.set_hook.html +/// +/// # 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 { +/// println!("panic occurred"); +/// } +/// })); +/// +/// panic!("Normal panic"); +/// ``` +#[lang = "panic_info"] +#[stable(feature = "panic_hooks", since = "1.10.0")] +#[derive(Debug)] +pub struct PanicInfo<'a> { + payload: &'a (dyn Any + Send), + message: Option<&'a fmt::Arguments<'a>>, + location: &'a Location<'a>, +} + +impl<'a> PanicInfo<'a> { + #[unstable( + feature = "panic_internals", + reason = "internal details of the implementation of the `panic!` and related macros", + issue = "none" + )] + #[doc(hidden)] + #[inline] + pub fn internal_constructor( + message: Option<&'a fmt::Arguments<'a>>, + location: &'a Location<'a>, + ) -> Self { + struct NoPayload; + PanicInfo { location, message, payload: &NoPayload } + } + + #[unstable( + feature = "panic_internals", + reason = "internal details of the implementation of the `panic!` and related macros", + issue = "none" + )] + #[doc(hidden)] + #[inline] + pub fn set_payload(&mut self, info: &'a (dyn Any + Send)) { + self.payload = info; + } + + /// Returns the payload associated with the panic. + /// + /// This will commonly, but not always, be a `&'static str` or [`String`]. + /// + /// [`String`]: ../../std/string/struct.String.html + /// + /// # 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 { + /// println!("panic occurred"); + /// } + /// })); + /// + /// panic!("Normal panic"); + /// ``` + #[stable(feature = "panic_hooks", since = "1.10.0")] + pub fn payload(&self) -> &(dyn Any + Send) { + self.payload + } + + /// If the `panic!` macro from the `core` crate (not from `std`) + /// was used with a formatting string and some additional arguments, + /// returns that message ready to be used for example with [`fmt::write`] + #[unstable(feature = "panic_info_message", issue = "66745")] + pub fn message(&self) -> Option<&fmt::Arguments<'_>> { + self.message + } + + /// 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"); + /// ``` + #[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 std::panicking::begin_panic_fmt. + Some(&self.location) + } +} + +#[stable(feature = "panic_hook_display", since = "1.26.0")] +impl fmt::Display for PanicInfo<'_> { + fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + formatter.write_str("panicked at ")?; + if let Some(message) = self.message { + write!(formatter, "'{}', ", message)? + } else if let Some(payload) = self.payload.downcast_ref::<&'static str>() { + write!(formatter, "'{}', ", payload)? + } + // NOTE: we cannot use downcast_ref::<String>() here + // since String is not available in libcore! + // The payload is a String when `std::panic!` is called with multiple arguments, + // but in that case the message is also available. + + self.location.fmt(formatter) + } +} diff --git a/library/core/src/panic/unwind_safe.rs b/library/core/src/panic/unwind_safe.rs new file mode 100644 index 00000000000..092b7cf0f2c --- /dev/null +++ b/library/core/src/panic/unwind_safe.rs @@ -0,0 +1,305 @@ +use crate::cell::UnsafeCell; +use crate::fmt; +use crate::future::Future; +use crate::ops::{Deref, DerefMut}; +use crate::pin::Pin; +use crate::ptr::{NonNull, Unique}; +use crate::stream::Stream; +use crate::task::{Context, Poll}; + +/// A marker trait which represents "panic safe" types in Rust. +/// +/// This trait is implemented by default for many types and behaves similarly in +/// terms of inference of implementation to the [`Send`] and [`Sync`] traits. The +/// purpose of this trait is to encode what types are safe to cross a [`catch_unwind`] +/// boundary with no fear of unwind safety. +/// +/// [`catch_unwind`]: ../../std/panic/fn.catch_unwind.html +/// +/// ## What is unwind safety? +/// +/// In Rust a function can "return" early if it either panics or calls a +/// function which transitively panics. This sort of control flow is not always +/// anticipated, and has the possibility of causing subtle bugs through a +/// combination of two critical components: +/// +/// 1. A data structure is in a temporarily invalid state when the thread +/// panics. +/// 2. This broken invariant is then later observed. +/// +/// Typically in Rust, it is difficult to perform step (2) because catching a +/// panic involves either spawning a thread (which in turns makes it difficult +/// to later witness broken invariants) or using the `catch_unwind` function in this +/// module. Additionally, even if an invariant is witnessed, it typically isn't a +/// problem in Rust because there are no uninitialized values (like in C or C++). +/// +/// It is possible, however, for **logical** invariants to be broken in Rust, +/// which can end up causing behavioral bugs. Another key aspect of unwind safety +/// in Rust is that, in the absence of `unsafe` code, a panic cannot lead to +/// memory unsafety. +/// +/// That was a bit of a whirlwind tour of unwind safety, but for more information +/// about unwind safety and how it applies to Rust, see an [associated RFC][rfc]. +/// +/// [rfc]: https://github.com/rust-lang/rfcs/blob/master/text/1236-stabilize-catch-panic.md +/// +/// ## What is `UnwindSafe`? +/// +/// Now that we've got an idea of what unwind safety is in Rust, it's also +/// important to understand what this trait represents. As mentioned above, one +/// way to witness broken invariants is through the `catch_unwind` function in this +/// module as it allows catching a panic and then re-using the environment of +/// the closure. +/// +/// Simply put, a type `T` implements `UnwindSafe` if it cannot easily allow +/// witnessing a broken invariant through the use of `catch_unwind` (catching a +/// panic). This trait is an auto trait, so it is automatically implemented for +/// many types, and it is also structurally composed (e.g., a struct is unwind +/// safe if all of its components are unwind safe). +/// +/// Note, however, that this is not an unsafe trait, so there is not a succinct +/// contract that this trait is providing. Instead it is intended as more of a +/// "speed bump" to alert users of `catch_unwind` that broken invariants may be +/// witnessed and may need to be accounted for. +/// +/// ## Who implements `UnwindSafe`? +/// +/// Types such as `&mut T` and `&RefCell<T>` are examples which are **not** +/// unwind safe. The general idea is that any mutable state which can be shared +/// across `catch_unwind` is not unwind safe by default. This is because it is very +/// easy to witness a broken invariant outside of `catch_unwind` as the data is +/// simply accessed as usual. +/// +/// Types like `&Mutex<T>`, however, are unwind safe because they implement +/// poisoning by default. They still allow witnessing a broken invariant, but +/// they already provide their own "speed bumps" to do so. +/// +/// ## When should `UnwindSafe` be used? +/// +/// It is not intended that most types or functions need to worry about this trait. +/// It is only used as a bound on the `catch_unwind` function and as mentioned +/// above, the lack of `unsafe` means it is mostly an advisory. The +/// [`AssertUnwindSafe`] wrapper struct can be used to force this trait to be +/// implemented for any closed over variables passed to `catch_unwind`. +#[stable(feature = "catch_unwind", since = "1.9.0")] +#[cfg_attr(not(test), rustc_diagnostic_item = "unwind_safe_trait")] +#[rustc_on_unimplemented( + message = "the type `{Self}` may not be safely transferred across an unwind boundary", + label = "`{Self}` may not be safely transferred across an unwind boundary" +)] +pub auto trait UnwindSafe {} + +/// A marker trait representing types where a shared reference is considered +/// unwind safe. +/// +/// This trait is namely not implemented by [`UnsafeCell`], the root of all +/// interior mutability. +/// +/// This is a "helper marker trait" used to provide impl blocks for the +/// [`UnwindSafe`] trait, for more information see that documentation. +#[stable(feature = "catch_unwind", since = "1.9.0")] +#[cfg_attr(not(test), rustc_diagnostic_item = "ref_unwind_safe_trait")] +#[rustc_on_unimplemented( + message = "the type `{Self}` may contain interior mutability and a reference may not be safely \ + transferrable across a catch_unwind boundary", + label = "`{Self}` may contain interior mutability and a reference may not be safely \ + transferrable across a catch_unwind boundary" +)] +pub auto trait RefUnwindSafe {} + +/// A simple wrapper around a type to assert that it is unwind safe. +/// +/// When using [`catch_unwind`] it may be the case that some of the closed over +/// variables are not unwind safe. For example if `&mut T` is captured the +/// compiler will generate a warning indicating that it is not unwind safe. It +/// might not be the case, however, that this is actually a problem due to the +/// specific usage of [`catch_unwind`] if unwind safety is specifically taken into +/// account. This wrapper struct is useful for a quick and lightweight +/// annotation that a variable is indeed unwind safe. +/// +/// [`catch_unwind`]: ../../std/panic/fn.catch_unwind.html +/// +/// # Examples +/// +/// One way to use `AssertUnwindSafe` is to assert that the entire closure +/// itself is unwind safe, bypassing all checks for all variables: +/// +/// ``` +/// use std::panic::{self, AssertUnwindSafe}; +/// +/// let mut variable = 4; +/// +/// // This code will not compile because the closure captures `&mut variable` +/// // which is not considered unwind safe by default. +/// +/// // panic::catch_unwind(|| { +/// // variable += 3; +/// // }); +/// +/// // This, however, will compile due to the `AssertUnwindSafe` wrapper +/// let result = panic::catch_unwind(AssertUnwindSafe(|| { +/// variable += 3; +/// })); +/// // ... +/// ``` +/// +/// Wrapping the entire closure amounts to a blanket assertion that all captured +/// variables are unwind safe. This has the downside that if new captures are +/// added in the future, they will also be considered unwind safe. Therefore, +/// you may prefer to just wrap individual captures, as shown below. This is +/// more annotation, but it ensures that if a new capture is added which is not +/// unwind safe, you will get a compilation error at that time, which will +/// allow you to consider whether that new capture in fact represent a bug or +/// not. +/// +/// ``` +/// use std::panic::{self, AssertUnwindSafe}; +/// +/// let mut variable = 4; +/// let other_capture = 3; +/// +/// let result = { +/// let mut wrapper = AssertUnwindSafe(&mut variable); +/// panic::catch_unwind(move || { +/// **wrapper += other_capture; +/// }) +/// }; +/// // ... +/// ``` +#[stable(feature = "catch_unwind", since = "1.9.0")] +pub struct AssertUnwindSafe<T>(#[stable(feature = "catch_unwind", since = "1.9.0")] pub T); + +// Implementations of the `UnwindSafe` trait: +// +// * By default everything is unwind safe +// * pointers T contains mutability of some form are not unwind safe +// * Unique, an owning pointer, lifts an implementation +// * Types like Mutex/RwLock which are explicitly poisoned are unwind safe +// * Our custom AssertUnwindSafe wrapper is indeed unwind safe + +#[stable(feature = "catch_unwind", since = "1.9.0")] +impl<T: ?Sized> !UnwindSafe for &mut T {} +#[stable(feature = "catch_unwind", since = "1.9.0")] +impl<T: RefUnwindSafe + ?Sized> UnwindSafe for &T {} +#[stable(feature = "catch_unwind", since = "1.9.0")] +impl<T: RefUnwindSafe + ?Sized> UnwindSafe for *const T {} +#[stable(feature = "catch_unwind", since = "1.9.0")] +impl<T: RefUnwindSafe + ?Sized> UnwindSafe for *mut T {} +#[unstable(feature = "ptr_internals", issue = "none")] +impl<T: UnwindSafe + ?Sized> UnwindSafe for Unique<T> {} +#[stable(feature = "nonnull", since = "1.25.0")] +impl<T: RefUnwindSafe + ?Sized> UnwindSafe for NonNull<T> {} +#[stable(feature = "catch_unwind", since = "1.9.0")] +impl<T> UnwindSafe for AssertUnwindSafe<T> {} + +// Pretty simple implementations for the `RefUnwindSafe` marker trait, +// basically just saying that `UnsafeCell` is the +// only thing which doesn't implement it (which then transitively applies to +// everything else). +#[stable(feature = "catch_unwind", since = "1.9.0")] +impl<T: ?Sized> !RefUnwindSafe for UnsafeCell<T> {} +#[stable(feature = "catch_unwind", since = "1.9.0")] +impl<T> RefUnwindSafe for AssertUnwindSafe<T> {} + +#[cfg(target_has_atomic_load_store = "ptr")] +#[stable(feature = "unwind_safe_atomic_refs", since = "1.14.0")] +impl RefUnwindSafe for crate::sync::atomic::AtomicIsize {} +#[cfg(target_has_atomic_load_store = "8")] +#[stable(feature = "integer_atomics_stable", since = "1.34.0")] +impl RefUnwindSafe for crate::sync::atomic::AtomicI8 {} +#[cfg(target_has_atomic_load_store = "16")] +#[stable(feature = "integer_atomics_stable", since = "1.34.0")] +impl RefUnwindSafe for crate::sync::atomic::AtomicI16 {} +#[cfg(target_has_atomic_load_store = "32")] +#[stable(feature = "integer_atomics_stable", since = "1.34.0")] +impl RefUnwindSafe for crate::sync::atomic::AtomicI32 {} +#[cfg(target_has_atomic_load_store = "64")] +#[stable(feature = "integer_atomics_stable", since = "1.34.0")] +impl RefUnwindSafe for crate::sync::atomic::AtomicI64 {} +#[cfg(target_has_atomic_load_store = "128")] +#[unstable(feature = "integer_atomics", issue = "32976")] +impl RefUnwindSafe for crate::sync::atomic::AtomicI128 {} + +#[cfg(target_has_atomic_load_store = "ptr")] +#[stable(feature = "unwind_safe_atomic_refs", since = "1.14.0")] +impl RefUnwindSafe for crate::sync::atomic::AtomicUsize {} +#[cfg(target_has_atomic_load_store = "8")] +#[stable(feature = "integer_atomics_stable", since = "1.34.0")] +impl RefUnwindSafe for crate::sync::atomic::AtomicU8 {} +#[cfg(target_has_atomic_load_store = "16")] +#[stable(feature = "integer_atomics_stable", since = "1.34.0")] +impl RefUnwindSafe for crate::sync::atomic::AtomicU16 {} +#[cfg(target_has_atomic_load_store = "32")] +#[stable(feature = "integer_atomics_stable", since = "1.34.0")] +impl RefUnwindSafe for crate::sync::atomic::AtomicU32 {} +#[cfg(target_has_atomic_load_store = "64")] +#[stable(feature = "integer_atomics_stable", since = "1.34.0")] +impl RefUnwindSafe for crate::sync::atomic::AtomicU64 {} +#[cfg(target_has_atomic_load_store = "128")] +#[unstable(feature = "integer_atomics", issue = "32976")] +impl RefUnwindSafe for crate::sync::atomic::AtomicU128 {} + +#[cfg(target_has_atomic_load_store = "8")] +#[stable(feature = "unwind_safe_atomic_refs", since = "1.14.0")] +impl RefUnwindSafe for crate::sync::atomic::AtomicBool {} + +#[cfg(target_has_atomic_load_store = "ptr")] +#[stable(feature = "unwind_safe_atomic_refs", since = "1.14.0")] +impl<T> RefUnwindSafe for crate::sync::atomic::AtomicPtr<T> {} + +#[stable(feature = "catch_unwind", since = "1.9.0")] +impl<T> Deref for AssertUnwindSafe<T> { + type Target = T; + + fn deref(&self) -> &T { + &self.0 + } +} + +#[stable(feature = "catch_unwind", since = "1.9.0")] +impl<T> DerefMut for AssertUnwindSafe<T> { + fn deref_mut(&mut self) -> &mut T { + &mut self.0 + } +} + +#[stable(feature = "catch_unwind", since = "1.9.0")] +impl<R, F: FnOnce() -> R> FnOnce<()> for AssertUnwindSafe<F> { + type Output = R; + + extern "rust-call" fn call_once(self, _args: ()) -> R { + (self.0)() + } +} + +#[stable(feature = "std_debug", since = "1.16.0")] +impl<T: fmt::Debug> fmt::Debug for AssertUnwindSafe<T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_tuple("AssertUnwindSafe").field(&self.0).finish() + } +} + +#[stable(feature = "futures_api", since = "1.36.0")] +impl<F: Future> Future for AssertUnwindSafe<F> { + type Output = F::Output; + + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { + // SAFETY: pin projection. AssertUnwindSafe follows structural pinning. + let pinned_field = unsafe { Pin::map_unchecked_mut(self, |x| &mut x.0) }; + F::poll(pinned_field, cx) + } +} + +#[unstable(feature = "async_stream", issue = "79024")] +impl<S: Stream> Stream for AssertUnwindSafe<S> { + type Item = S::Item; + + fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<S::Item>> { + // SAFETY: pin projection. AssertUnwindSafe follows structural pinning. + unsafe { self.map_unchecked_mut(|x| &mut x.0) }.poll_next(cx) + } + + fn size_hint(&self) -> (usize, Option<usize>) { + self.0.size_hint() + } +} diff --git a/library/core/src/panicking.rs b/library/core/src/panicking.rs index 3e3e96fcd7f..2ec6b4d15ff 100644 --- a/library/core/src/panicking.rs +++ b/library/core/src/panicking.rs @@ -74,6 +74,7 @@ fn panic_bounds_check(index: usize, len: usize) -> ! { #[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))] #[cfg_attr(feature = "panic_immediate_abort", inline)] #[track_caller] +#[cfg_attr(not(bootstrap), lang = "panic_fmt")] // needed for const-evaluated panics pub fn panic_fmt(fmt: fmt::Arguments<'_>) -> ! { if cfg!(feature = "panic_immediate_abort") { super::intrinsics::abort() @@ -92,6 +93,20 @@ pub fn panic_fmt(fmt: fmt::Arguments<'_>) -> ! { unsafe { panic_impl(&pi) } } +/// This function is used instead of panic_fmt in const eval. +#[cfg(not(bootstrap))] +#[lang = "const_panic_fmt"] +pub const fn const_panic_fmt(fmt: fmt::Arguments<'_>) -> ! { + if let Some(msg) = fmt.as_str() { + panic_str(msg); + } else { + // SAFETY: This is only evaluated at compile time, which reliably + // handles this UB (in case this branch turns out to be reachable + // somehow). + unsafe { crate::hint::unreachable_unchecked() }; + } +} + #[derive(Debug)] #[doc(hidden)] pub enum AssertKind { diff --git a/library/core/src/pin.rs b/library/core/src/pin.rs index 3d888299485..6a1a84bafa3 100644 --- a/library/core/src/pin.rs +++ b/library/core/src/pin.rs @@ -159,9 +159,9 @@ //! section needs to function correctly. //! //! Notice that this guarantee does *not* mean that memory does not leak! It is still -//! completely okay not ever to call [`drop`] on a pinned element (e.g., you can still +//! completely okay to not ever call [`drop`] on a pinned element (e.g., you can still //! call [`mem::forget`] on a <code>[Pin]<[Box]\<T>></code>). In the example of the doubly-linked -//! list, that element would just stay in the list. However you may not free or reuse the storage +//! list, that element would just stay in the list. However you must not free or reuse the storage //! *without calling [`drop`]*. //! //! # `Drop` implementation @@ -802,6 +802,44 @@ impl<T: ?Sized> Pin<&'static T> { } } +impl<'a, P: DerefMut> Pin<&'a mut Pin<P>> { + /// Gets a pinned mutable reference from this nested pinned pointer. + /// + /// This is a generic method to go from `Pin<&mut Pin<Pointer<T>>>` to `Pin<&mut T>`. It is + /// safe because the existence of a `Pin<Pointer<T>>` ensures that the pointee, `T`, cannot + /// move in the future, and this method does not enable the pointee to move. "Malicious" + /// implementations of `P::DerefMut` are likewise ruled out by the contract of + /// `Pin::new_unchecked`. + #[unstable(feature = "pin_deref_mut", issue = "86918")] + #[inline(always)] + pub fn as_deref_mut(self) -> Pin<&'a mut P::Target> { + // SAFETY: What we're asserting here is that going from + // + // Pin<&mut Pin<P>> + // + // to + // + // Pin<&mut P::Target> + // + // is safe. + // + // We need to ensure that two things hold for that to be the case: + // + // 1) Once we give out a `Pin<&mut P::Target>`, an `&mut P::Target` will not be given out. + // 2) By giving out a `Pin<&mut P::Target>`, we do not risk of violating `Pin<&mut Pin<P>>` + // + // The existence of `Pin<P>` is sufficient to guarantee #1: since we already have a + // `Pin<P>`, it must already uphold the pinning guarantees, which must mean that + // `Pin<&mut P::Target>` does as well, since `Pin::as_mut` is safe. We do not have to rely + // on the fact that P is _also_ pinned. + // + // For #2, we need to ensure that code given a `Pin<&mut P::Target>` cannot cause the + // `Pin<P>` to move? That is not possible, since `Pin<&mut P::Target>` no longer retains + // any access to the `P` itself, much less the `Pin<P>`. + unsafe { self.get_unchecked_mut() }.as_mut() + } +} + impl<T: ?Sized> Pin<&'static mut T> { /// Get a pinned mutable reference from a static mutable reference. /// diff --git a/library/core/src/prelude/mod.rs b/library/core/src/prelude/mod.rs index 79753c1fb66..ccd36a428e2 100644 --- a/library/core/src/prelude/mod.rs +++ b/library/core/src/prelude/mod.rs @@ -11,9 +11,9 @@ pub mod v1; /// The 2015 version of the core prelude. /// /// See the [module-level documentation](self) for more. -#[unstable(feature = "prelude_2015", issue = "85684")] +#[stable(feature = "prelude_2015", since = "1.55.0")] pub mod rust_2015 { - #[unstable(feature = "prelude_2015", issue = "85684")] + #[stable(feature = "prelude_2015", since = "1.55.0")] #[doc(no_inline)] pub use super::v1::*; } @@ -21,9 +21,9 @@ pub mod rust_2015 { /// The 2018 version of the core prelude. /// /// See the [module-level documentation](self) for more. -#[unstable(feature = "prelude_2018", issue = "85684")] +#[stable(feature = "prelude_2018", since = "1.55.0")] pub mod rust_2018 { - #[unstable(feature = "prelude_2018", issue = "85684")] + #[stable(feature = "prelude_2018", since = "1.55.0")] #[doc(no_inline)] pub use super::v1::*; } @@ -31,17 +31,17 @@ pub mod rust_2018 { /// The 2021 version of the core prelude. /// /// See the [module-level documentation](self) for more. -#[unstable(feature = "prelude_2021", issue = "85684")] +#[stable(feature = "prelude_2021", since = "1.55.0")] pub mod rust_2021 { - #[unstable(feature = "prelude_2021", issue = "85684")] + #[stable(feature = "prelude_2021", since = "1.55.0")] #[doc(no_inline)] pub use super::v1::*; - #[unstable(feature = "prelude_2021", issue = "85684")] + #[stable(feature = "prelude_2021", since = "1.55.0")] #[doc(no_inline)] pub use crate::iter::FromIterator; - #[unstable(feature = "prelude_2021", issue = "85684")] + #[stable(feature = "prelude_2021", since = "1.55.0")] #[doc(no_inline)] pub use crate::convert::{TryFrom, TryInto}; } diff --git a/library/core/src/prelude/v1.rs b/library/core/src/prelude/v1.rs index c89fe57cb05..6b51ef5b012 100644 --- a/library/core/src/prelude/v1.rs +++ b/library/core/src/prelude/v1.rs @@ -55,11 +55,27 @@ pub use crate::hash::macros::Hash; #[allow(deprecated)] #[doc(no_inline)] pub use crate::{ - asm, assert, cfg, column, compile_error, concat, concat_idents, env, file, format_args, - format_args_nl, global_asm, include, include_bytes, include_str, line, llvm_asm, log_syntax, - module_path, option_env, stringify, trace_macros, + assert, cfg, column, compile_error, concat, concat_idents, env, file, format_args, + format_args_nl, include, include_bytes, include_str, line, llvm_asm, log_syntax, module_path, + option_env, stringify, trace_macros, }; +#[unstable( + feature = "asm", + issue = "72016", + reason = "inline assembly is not stable enough for use and is subject to change" +)] +#[doc(no_inline)] +pub use crate::arch::asm; + +#[unstable( + feature = "global_asm", + issue = "35119", + reason = "`global_asm!` is not stable enough for use and is subject to change" +)] +#[doc(no_inline)] +pub use crate::arch::global_asm; + #[stable(feature = "builtin_macro_prelude", since = "1.38.0")] #[allow(deprecated, deprecated_in_future)] #[doc(no_inline)] diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs index 8348afb2a56..95e86a688be 100644 --- a/library/core/src/ptr/const_ptr.rs +++ b/library/core/src/ptr/const_ptr.rs @@ -48,7 +48,7 @@ impl<T: ?Sized> *const T { self as _ } - /// Decompose a (possibly wide) pointer into is address and metadata components. + /// Decompose a (possibly wide) pointer into its address and metadata components. /// /// The pointer can be later reconstructed with [`from_raw_parts`]. #[unstable(feature = "ptr_metadata", issue = "81513")] @@ -244,7 +244,7 @@ impl<T: ?Sized> *const T { /// /// This operation itself is always safe, but using the resulting pointer is not. /// - /// The resulting pointer "remembers" the [allocated object] that `self` points to; it may not + /// The resulting pointer "remembers" the [allocated object] that `self` points to; it must not /// be used to read or write other allocated objects. /// /// In other words, `let z = x.wrapping_offset((y as isize) - (x as isize))` does *not* make `z` @@ -404,7 +404,7 @@ impl<T: ?Sized> *const T { /// /// [`guaranteed_ne`]: #method.guaranteed_ne /// - /// The return value may change depending on the compiler version and unsafe code may not + /// The return value may change depending on the compiler version and unsafe code might not /// rely on the result of this function for soundness. It is suggested to only use this function /// for performance optimizations where spurious `false` return values by this function do not /// affect the outcome, but just the performance. @@ -435,7 +435,7 @@ impl<T: ?Sized> *const T { /// /// [`guaranteed_eq`]: #method.guaranteed_eq /// - /// The return value may change depending on the compiler version and unsafe code may not + /// The return value may change depending on the compiler version and unsafe code might not /// rely on the result of this function for soundness. It is suggested to only use this function /// for performance optimizations where spurious `false` return values by this function do not /// affect the outcome, but just the performance. @@ -590,7 +590,7 @@ impl<T: ?Sized> *const T { /// /// This operation itself is always safe, but using the resulting pointer is not. /// - /// The resulting pointer "remembers" the [allocated object] that `self` points to; it may not + /// The resulting pointer "remembers" the [allocated object] that `self` points to; it must not /// be used to read or write other allocated objects. /// /// In other words, `let z = x.wrapping_add((y as usize) - (x as usize))` does *not* make `z` @@ -652,7 +652,7 @@ impl<T: ?Sized> *const T { /// /// This operation itself is always safe, but using the resulting pointer is not. /// - /// The resulting pointer "remembers" the [allocated object] that `self` points to; it may not + /// The resulting pointer "remembers" the [allocated object] that `self` points to; it must not /// be used to read or write other allocated objects. /// /// In other words, `let z = x.wrapping_sub((x as usize) - (y as usize))` does *not* make `z` diff --git a/library/core/src/ptr/metadata.rs b/library/core/src/ptr/metadata.rs index 7c7dce0ce74..287ae69acd1 100644 --- a/library/core/src/ptr/metadata.rs +++ b/library/core/src/ptr/metadata.rs @@ -101,7 +101,7 @@ pub const fn metadata<T: ?Sized>(ptr: *const T) -> <T as Pointee>::Metadata { /// /// This function is safe but the returned pointer is not necessarily safe to dereference. /// For slices, see the documentation of [`slice::from_raw_parts`] for safety requirements. -/// For trait objects, the metadata must come from a pointer to the same underlying ereased type. +/// For trait objects, the metadata must come from a pointer to the same underlying erased type. /// /// [`slice::from_raw_parts`]: crate::slice::from_raw_parts #[unstable(feature = "ptr_metadata", issue = "81513")] diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs index 214d7c8bc15..47fad15e333 100644 --- a/library/core/src/ptr/mod.rs +++ b/library/core/src/ptr/mod.rs @@ -685,6 +685,13 @@ pub const unsafe fn replace<T>(dst: *mut T, mut src: T) -> T { #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_unstable(feature = "const_ptr_read", issue = "80377")] pub const unsafe fn read<T>(src: *const T) -> T { + // We are calling the intrinsics directly to avoid function calls in the generated code + // as `intrinsics::copy_nonoverlapping` is a wrapper function. + extern "rust-intrinsic" { + #[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")] + fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize); + } + let mut tmp = MaybeUninit::<T>::uninit(); // SAFETY: the caller must guarantee that `src` is valid for reads. // `src` cannot overlap `tmp` because `tmp` was just allocated on @@ -871,14 +878,20 @@ pub const unsafe fn read_unaligned<T>(src: *const T) -> T { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_const_unstable(feature = "const_ptr_write", issue = "none")] +#[rustc_const_unstable(feature = "const_ptr_write", issue = "86302")] pub const unsafe fn write<T>(dst: *mut T, src: T) { + // We are calling the intrinsics directly to avoid function calls in the generated code + // as `intrinsics::copy_nonoverlapping` is a wrapper function. + extern "rust-intrinsic" { + #[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")] + fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize); + } + // SAFETY: the caller must guarantee that `dst` is valid for writes. // `dst` cannot overlap `src` because the caller has mutable access // to `dst` while `src` is owned by this function. unsafe { copy_nonoverlapping(&src as *const T, dst, 1); - // We are calling the intrinsic directly to avoid function calls in the generated code. intrinsics::forget(src); } } @@ -962,7 +975,7 @@ pub const unsafe fn write<T>(dst: *mut T, src: T) { /// ``` #[inline] #[stable(feature = "ptr_unaligned", since = "1.17.0")] -#[rustc_const_unstable(feature = "const_ptr_write", issue = "none")] +#[rustc_const_unstable(feature = "const_ptr_write", issue = "86302")] pub const unsafe fn write_unaligned<T>(dst: *mut T, src: T) { // SAFETY: the caller must guarantee that `dst` is valid for writes. // `dst` cannot overlap `src` because the caller has mutable access diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index 750279ac0db..adc64cb2bd3 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -47,7 +47,7 @@ impl<T: ?Sized> *mut T { self as _ } - /// Decompose a (possibly wide) pointer into is address and metadata components. + /// Decompose a (possibly wide) pointer into its address and metadata components. /// /// The pointer can be later reconstructed with [`from_raw_parts_mut`]. #[unstable(feature = "ptr_metadata", issue = "81513")] @@ -250,7 +250,7 @@ impl<T: ?Sized> *mut T { /// /// This operation itself is always safe, but using the resulting pointer is not. /// - /// The resulting pointer "remembers" the [allocated object] that `self` points to; it may not + /// The resulting pointer "remembers" the [allocated object] that `self` points to; it must not /// be used to read or write other allocated objects. /// /// In other words, `let z = x.wrapping_offset((y as isize) - (x as isize))` does *not* make `z` @@ -419,7 +419,7 @@ impl<T: ?Sized> *mut T { /// /// [`guaranteed_ne`]: #method.guaranteed_ne /// - /// The return value may change depending on the compiler version and unsafe code may not + /// The return value may change depending on the compiler version and unsafe code might not /// rely on the result of this function for soundness. It is suggested to only use this function /// for performance optimizations where spurious `false` return values by this function do not /// affect the outcome, but just the performance. @@ -450,7 +450,7 @@ impl<T: ?Sized> *mut T { /// /// [`guaranteed_eq`]: #method.guaranteed_eq /// - /// The return value may change depending on the compiler version and unsafe code may not + /// The return value may change depending on the compiler version and unsafe code might not /// rely on the result of this function for soundness. It is suggested to only use this function /// for performance optimizations where spurious `false` return values by this function do not /// affect the outcome, but just the performance. @@ -596,6 +596,7 @@ impl<T: ?Sized> *mut T { /// enables more aggressive compiler optimizations. /// /// [`wrapping_add`]: #method.wrapping_add + /// [allocated object]: crate::ptr#allocated-object /// /// # Examples /// @@ -696,7 +697,7 @@ impl<T: ?Sized> *mut T { /// /// This operation itself is always safe, but using the resulting pointer is not. /// - /// The resulting pointer "remembers" the [allocated object] that `self` points to; it may not + /// The resulting pointer "remembers" the [allocated object] that `self` points to; it must not /// be used to read or write other allocated objects. /// /// In other words, `let z = x.wrapping_add((y as usize) - (x as usize))` does *not* make `z` @@ -758,7 +759,7 @@ impl<T: ?Sized> *mut T { /// /// This operation itself is always safe, but using the resulting pointer is not. /// - /// The resulting pointer "remembers" the [allocated object] that `self` points to; it may not + /// The resulting pointer "remembers" the [allocated object] that `self` points to; it must not /// be used to read or write other allocated objects. /// /// In other words, `let z = x.wrapping_sub((x as usize) - (y as usize))` does *not* make `z` @@ -1002,7 +1003,7 @@ impl<T: ?Sized> *mut T { /// /// [`ptr::write`]: crate::ptr::write() #[stable(feature = "pointer_methods", since = "1.26.0")] - #[rustc_const_unstable(feature = "const_ptr_write", issue = "none")] + #[rustc_const_unstable(feature = "const_ptr_write", issue = "86302")] #[inline(always)] pub const unsafe fn write(self, val: T) where @@ -1057,7 +1058,7 @@ impl<T: ?Sized> *mut T { /// /// [`ptr::write_unaligned`]: crate::ptr::write_unaligned() #[stable(feature = "pointer_methods", since = "1.26.0")] - #[rustc_const_unstable(feature = "const_ptr_write", issue = "none")] + #[rustc_const_unstable(feature = "const_ptr_write", issue = "86302")] #[inline(always)] pub const unsafe fn write_unaligned(self, val: T) where diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs index 1c65518af04..87c8674af0d 100644 --- a/library/core/src/ptr/non_null.rs +++ b/library/core/src/ptr/non_null.rs @@ -71,6 +71,16 @@ impl<T: Sized> NonNull<T> { /// a `T`, which means this must not be used as a "not yet initialized" /// sentinel value. Types that lazily allocate must track initialization by /// some other means. + /// + /// # Examples + /// + /// ``` + /// use std::ptr::NonNull; + /// + /// let ptr = NonNull::<u32>::dangling(); + /// // Important: don't try to access the value of `ptr` without + /// // initializing it first! The pointer is not null but isn't valid either! + /// ``` #[stable(feature = "nonnull", since = "1.25.0")] #[rustc_const_stable(feature = "const_nonnull_dangling", since = "1.36.0")] #[inline] @@ -155,6 +165,24 @@ impl<T: ?Sized> NonNull<T> { /// # Safety /// /// `ptr` must be non-null. + /// + /// # Examples + /// + /// ``` + /// use std::ptr::NonNull; + /// + /// let mut x = 0u32; + /// let ptr = unsafe { NonNull::new_unchecked(&mut x as *mut _) }; + /// ``` + /// + /// *Incorrect* usage of this function: + /// + /// ```rust,no_run + /// use std::ptr::NonNull; + /// + /// // NEVER DO THAT!!! This is undefined behavior. ⚠️ + /// let ptr = unsafe { NonNull::<u32>::new_unchecked(std::ptr::null_mut()) }; + /// ``` #[stable(feature = "nonnull", since = "1.25.0")] #[rustc_const_stable(feature = "const_nonnull_new_unchecked", since = "1.25.0")] #[inline] @@ -164,6 +192,19 @@ impl<T: ?Sized> NonNull<T> { } /// Creates a new `NonNull` if `ptr` is non-null. + /// + /// # Examples + /// + /// ``` + /// use std::ptr::NonNull; + /// + /// let mut x = 0u32; + /// let ptr = NonNull::<u32>::new(&mut x as *mut _).expect("ptr is null!"); + /// + /// if let Some(ptr) = NonNull::<u32>::new(std::ptr::null_mut()) { + /// unreachable!(); + /// } + /// ``` #[stable(feature = "nonnull", since = "1.25.0")] #[inline] pub fn new(ptr: *mut T) -> Option<Self> { @@ -194,7 +235,7 @@ impl<T: ?Sized> NonNull<T> { } } - /// Decompose a (possibly wide) pointer into is address and metadata components. + /// Decompose a (possibly wide) pointer into its address and metadata components. /// /// The pointer can be later reconstructed with [`NonNull::from_raw_parts`]. #[unstable(feature = "ptr_metadata", issue = "81513")] @@ -205,6 +246,22 @@ impl<T: ?Sized> NonNull<T> { } /// Acquires the underlying `*mut` pointer. + /// + /// # Examples + /// + /// ``` + /// use std::ptr::NonNull; + /// + /// let mut x = 0u32; + /// let ptr = NonNull::new(&mut x).expect("ptr is null!"); + /// + /// let x_value = unsafe { *ptr.as_ptr() }; + /// assert_eq!(x_value, 0); + /// + /// unsafe { *ptr.as_ptr() += 2; } + /// let x_value = unsafe { *ptr.as_ptr() }; + /// assert_eq!(x_value, 2); + /// ``` #[stable(feature = "nonnull", since = "1.25.0")] #[rustc_const_stable(feature = "const_nonnull_as_ptr", since = "1.32.0")] #[inline] @@ -239,6 +296,18 @@ impl<T: ?Sized> NonNull<T> { /// (The part about being initialized is not yet fully decided, but until /// it is, the only safe approach is to ensure that they are indeed initialized.) /// + /// # Examples + /// + /// ``` + /// use std::ptr::NonNull; + /// + /// let mut x = 0u32; + /// let ptr = NonNull::new(&mut x as *mut _).expect("ptr is null!"); + /// + /// let ref_x = unsafe { ptr.as_ref() }; + /// println!("{}", ref_x); + /// ``` + /// /// [the module documentation]: crate::ptr#safety #[stable(feature = "nonnull", since = "1.25.0")] #[inline] @@ -274,6 +343,19 @@ impl<T: ?Sized> NonNull<T> { /// This applies even if the result of this method is unused! /// (The part about being initialized is not yet fully decided, but until /// it is, the only safe approach is to ensure that they are indeed initialized.) + /// # Examples + /// + /// ``` + /// use std::ptr::NonNull; + /// + /// let mut x = 0u32; + /// let mut ptr = NonNull::new(&mut x).expect("null pointer"); + /// + /// let x_ref = unsafe { ptr.as_mut() }; + /// assert_eq!(*x_ref, 0); + /// *x_ref += 2; + /// assert_eq!(*x_ref, 2); + /// ``` /// /// [the module documentation]: crate::ptr#safety #[stable(feature = "nonnull", since = "1.25.0")] @@ -285,6 +367,18 @@ impl<T: ?Sized> NonNull<T> { } /// Casts to a pointer of another type. + /// + /// # Examples + /// + /// ``` + /// use std::ptr::NonNull; + /// + /// let mut x = 0u32; + /// let ptr = NonNull::new(&mut x as *mut _).expect("null pointer"); + /// + /// let casted_ptr = ptr.cast::<i8>(); + /// let raw_ptr: *mut i8 = casted_ptr.as_ptr(); + /// ``` #[stable(feature = "nonnull_cast", since = "1.27.0")] #[rustc_const_stable(feature = "const_nonnull_cast", since = "1.36.0")] #[inline] diff --git a/library/core/src/raw.rs b/library/core/src/raw.rs deleted file mode 100644 index 6d1e28f4cd7..00000000000 --- a/library/core/src/raw.rs +++ /dev/null @@ -1,90 +0,0 @@ -#![allow(missing_docs)] -#![unstable(feature = "raw", issue = "27751")] -#![rustc_deprecated( - since = "1.53.0", - reason = "use pointer metadata APIs instead https://github.com/rust-lang/rust/issues/81513" -)] - -//! Contains struct definitions for the layout of compiler built-in types. -//! -//! They can be used as targets of transmutes in unsafe code for manipulating -//! the raw representations directly. -//! -//! Their definition should always match the ABI defined in -//! `rustc_middle::ty::layout`. - -/// The representation of a trait object like `&dyn SomeTrait`. -/// -/// This struct has the same layout as types like `&dyn SomeTrait` and -/// `Box<dyn AnotherTrait>`. -/// -/// `TraitObject` is guaranteed to match layouts, but it is not the -/// type of trait objects (e.g., the fields are not directly accessible -/// on a `&dyn SomeTrait`) nor does it control that layout (changing the -/// definition will not change the layout of a `&dyn SomeTrait`). It is -/// only designed to be used by unsafe code that needs to manipulate -/// the low-level details. -/// -/// There is no way to refer to all trait objects generically, so the only -/// way to create values of this type is with functions like -/// [`std::mem::transmute`][transmute]. Similarly, the only way to create a true -/// trait object from a `TraitObject` value is with `transmute`. -/// -/// [transmute]: crate::intrinsics::transmute -/// -/// Synthesizing a trait object with mismatched types—one where the -/// vtable does not correspond to the type of the value to which the -/// data pointer points—is highly likely to lead to undefined -/// behavior. -/// -/// # Examples -/// -/// ``` -/// #![feature(raw)] -/// -/// use std::{mem, raw}; -/// -/// // an example trait -/// trait Foo { -/// fn bar(&self) -> i32; -/// } -/// -/// impl Foo for i32 { -/// fn bar(&self) -> i32 { -/// *self + 1 -/// } -/// } -/// -/// let value: i32 = 123; -/// -/// // let the compiler make a trait object -/// let object: &dyn Foo = &value; -/// -/// // look at the raw representation -/// let raw_object: raw::TraitObject = unsafe { mem::transmute(object) }; -/// -/// // the data pointer is the address of `value` -/// assert_eq!(raw_object.data as *const i32, &value as *const _); -/// -/// let other_value: i32 = 456; -/// -/// // construct a new object, pointing to a different `i32`, being -/// // careful to use the `i32` vtable from `object` -/// let synthesized: &dyn Foo = unsafe { -/// mem::transmute(raw::TraitObject { -/// data: &other_value as *const _ as *mut (), -/// vtable: raw_object.vtable, -/// }) -/// }; -/// -/// // it should work just as if we had constructed a trait object out of -/// // `other_value` directly -/// assert_eq!(synthesized.bar(), 457); -/// ``` -#[repr(C)] -#[derive(Copy, Clone)] -#[allow(missing_debug_implementations)] -pub struct TraitObject { - pub data: *mut (), - pub vtable: *mut (), -} diff --git a/library/core/src/result.rs b/library/core/src/result.rs index babd0a0b552..861790e8a40 100644 --- a/library/core/src/result.rs +++ b/library/core/src/result.rs @@ -224,6 +224,268 @@ //! [`Ok(T)`]: Ok //! [`Err(E)`]: Err //! [`io::Error`]: ../../std/io/struct.Error.html +//! +//! # Method overview +//! +//! In addition to working with pattern matching, [`Result`] provides a +//! wide variety of different methods. +//! +//! ## Querying the variant +//! +//! The [`is_ok`] and [`is_err`] methods return [`true`] if the [`Result`] +//! is [`Ok`] or [`Err`], respectively. +//! +//! [`is_err`]: Result::is_err +//! [`is_ok`]: Result::is_ok +//! +//! ## Adapters for working with references +//! +//! * [`as_ref`] converts from `&Result<T, E>` to `Result<&T, &E>` +//! * [`as_mut`] converts from `&mut Result<T, E>` to `Result<&mut T, &mut E>` +//! * [`as_deref`] converts from `&Result<T, E>` to `Result<&T::Target, &E>` +//! * [`as_deref_mut`] converts from `&mut Result<T, E>` to +//! `Result<&mut T::Target, &mut E>` +//! +//! [`as_deref`]: Result::as_deref +//! [`as_deref_mut`]: Result::as_deref_mut +//! [`as_mut`]: Result::as_mut +//! [`as_ref`]: Result::as_ref +//! +//! ## Extracting contained values +//! +//! These methods extract the contained value in a [`Result<T, E>`] when it +//! is the [`Ok`] variant. If the [`Result`] is [`Err`]: +//! +//! * [`expect`] panics with a provided custom message +//! * [`unwrap`] panics with a generic message +//! * [`unwrap_or`] returns the provided default value +//! * [`unwrap_or_default`] returns the default value of the type `T` +//! (which must implement the [`Default`] trait) +//! * [`unwrap_or_else`] returns the result of evaluating the provided +//! function +//! +//! The panicking methods [`expect`] and [`unwrap`] require `E` to +//! implement the [`Debug`] trait. +//! +//! [`Debug`]: crate::fmt::Debug +//! [`expect`]: Result::expect +//! [`unwrap`]: Result::unwrap +//! [`unwrap_or`]: Result::unwrap_or +//! [`unwrap_or_default`]: Result::unwrap_or_default +//! [`unwrap_or_else`]: Result::unwrap_or_else +//! +//! These methods extract the contained value in a [`Result<T, E>`] when it +//! is the [`Err`] variant. They require `T` to implement the [`Debug`] +//! trait. If the [`Result`] is [`Ok`]: +//! +//! * [`expect_err`] panics with a provided custom message +//! * [`unwrap_err`] panics with a generic message +//! +//! [`Debug`]: crate::fmt::Debug +//! [`expect_err`]: Result::expect_err +//! [`unwrap_err`]: Result::unwrap_err +//! +//! ## Transforming contained values +//! +//! These methods transform [`Result`] to [`Option`]: +//! +//! * [`err`][Result::err] transforms [`Result<T, E>`] into [`Option<E>`], +//! mapping [`Err(e)`] to [`Some(e)`] and [`Ok(v)`] to [`None`] +//! * [`ok`][Result::ok] transforms [`Result<T, E>`] into [`Option<T>`], +//! mapping [`Ok(v)`] to [`Some(v)`] and [`Err(e)`] to [`None`] +//! * [`transpose`] transposes a [`Result`] of an [`Option`] into an +//! [`Option`] of a [`Result`] +//! +// Do NOT add link reference definitions for `err` or `ok`, because they +// will generate numerous incorrect URLs for `Err` and `Ok` elsewhere, due +// to case folding. +//! +//! [`Err(e)`]: Err +//! [`Ok(v)`]: Ok +//! [`Some(e)`]: Option::Some +//! [`Some(v)`]: Option::Some +//! [`transpose`]: Result::transpose +//! +//! This method transforms the contained value of the [`Ok`] variant: +//! +//! * [`map`] transforms [`Result<T, E>`] into [`Result<U, E>`] by applying +//! the provided function to the contained value of [`Ok`] and leaving +//! [`Err`] values unchanged +//! +//! [`map`]: Result::map +//! +//! This method transforms the contained value of the [`Err`] variant: +//! +//! * [`map_err`] transforms [`Result<T, E>`] into [`Result<T, F>`] by +//! applying the provided function to the contained value of [`Err`] and +//! leaving [`Ok`] values unchanged +//! +//! [`map_err`]: Result::map_err +//! +//! These methods transform a [`Result<T, E>`] into a value of a possibly +//! different type `U`: +//! +//! * [`map_or`] applies the provided function to the contained value of +//! [`Ok`], or returns the provided default value if the [`Result`] is +//! [`Err`] +//! * [`map_or_else`] applies the provided function to the contained value +//! of [`Ok`], or applies the provided fallback function to the contained +//! value of [`Err`] +//! +//! [`map_or`]: Result::map_or +//! [`map_or_else`]: Result::map_or_else +//! +//! ## Boolean operators +//! +//! These methods treat the [`Result`] as a boolean value, where [`Ok`] +//! acts like [`true`] and [`Err`] acts like [`false`]. There are two +//! categories of these methods: ones that take a [`Result`] as input, and +//! ones that take a function as input (to be lazily evaluated). +//! +//! The [`and`] and [`or`] methods take another [`Result`] as input, and +//! produce a [`Result`] as output. The [`and`] method can produce a +//! [`Result<U, E>`] value having a different inner type `U` than +//! [`Result<T, E>`]. The [`or`] method can produce a [`Result<T, F>`] +//! value having a different error type `F` than [`Result<T, E>`]. +//! +//! | method | self | input | output | +//! |---------|----------|-----------|----------| +//! | [`and`] | `Err(e)` | (ignored) | `Err(e)` | +//! | [`and`] | `Ok(x)` | `Err(d)` | `Err(d)` | +//! | [`and`] | `Ok(x)` | `Ok(y)` | `Ok(y)` | +//! | [`or`] | `Err(e)` | `Err(d)` | `Err(d)` | +//! | [`or`] | `Err(e)` | `Ok(y)` | `Ok(y)` | +//! | [`or`] | `Ok(x)` | (ignored) | `Ok(x)` | +//! +//! [`and`]: Result::and +//! [`or`]: Result::or +//! +//! The [`and_then`] and [`or_else`] methods take a function as input, and +//! only evaluate the function when they need to produce a new value. The +//! [`and_then`] method can produce a [`Result<U, E>`] value having a +//! different inner type `U` than [`Result<T, E>`]. The [`or_else`] method +//! can produce a [`Result<T, F>`] value having a different error type `F` +//! than [`Result<T, E>`]. +//! +//! | method | self | function input | function result | output | +//! |--------------|----------|----------------|-----------------|----------| +//! | [`and_then`] | `Err(e)` | (not provided) | (not evaluated) | `Err(e)` | +//! | [`and_then`] | `Ok(x)` | `x` | `Err(d)` | `Err(d)` | +//! | [`and_then`] | `Ok(x)` | `x` | `Ok(y)` | `Ok(y)` | +//! | [`or_else`] | `Err(e)` | `e` | `Err(d)` | `Err(d)` | +//! | [`or_else`] | `Err(e)` | `e` | `Ok(y)` | `Ok(y)` | +//! | [`or_else`] | `Ok(x)` | (not provided) | (not evaluated) | `Ok(x)` | +//! +//! [`and_then`]: Result::and_then +//! [`or_else`]: Result::or_else +//! +//! ## Comparison operators +//! +//! If `T` and `E` both implement [`PartialOrd`] then [`Result<T, E>`] will +//! derive its [`PartialOrd`] implementation. With this order, an [`Ok`] +//! compares as less than any [`Err`], while two [`Ok`] or two [`Err`] +//! compare as their contained values would in `T` or `E` respectively. If `T` +//! and `E` both also implement [`Ord`], then so does [`Result<T, E>`]. +//! +//! ``` +//! assert!(Ok(1) < Err(0)); +//! let x: Result<i32, ()> = Ok(0); +//! let y = Ok(1); +//! assert!(x < y); +//! let x: Result<(), i32> = Err(0); +//! let y = Err(1); +//! assert!(x < y); +//! ``` +//! +//! ## Iterating over `Result` +//! +//! A [`Result`] can be iterated over. This can be helpful if you need an +//! iterator that is conditionally empty. The iterator will either produce +//! a single value (when the [`Result`] is [`Ok`]), or produce no values +//! (when the [`Result`] is [`Err`]). For example, [`into_iter`] acts like +//! [`once(v)`] if the [`Result`] is [`Ok(v)`], and like [`empty()`] if the +//! [`Result`] is [`Err`]. +//! +//! [`Ok(v)`]: Ok +//! [`empty()`]: crate::iter::empty +//! [`once(v)`]: crate::iter::once +//! +//! Iterators over [`Result<T, E>`] come in three types: +//! +//! * [`into_iter`] consumes the [`Result`] and produces the contained +//! value +//! * [`iter`] produces an immutable reference of type `&T` to the +//! contained value +//! * [`iter_mut`] produces a mutable reference of type `&mut T` to the +//! contained value +//! +//! See [Iterating over `Option`] for examples of how this can be useful. +//! +//! [Iterating over `Option`]: crate::option#iterating-over-option +//! [`into_iter`]: Result::into_iter +//! [`iter`]: Result::iter +//! [`iter_mut`]: Result::iter_mut +//! +//! You might want to use an iterator chain to do multiple instances of an +//! operation that can fail, but would like to ignore failures while +//! continuing to process the successful results. In this example, we take +//! advantage of the iterable nature of [`Result`] to select only the +//! [`Ok`] values using [`flatten`][Iterator::flatten]. +//! +//! ``` +//! # use std::str::FromStr; +//! let mut results = vec![]; +//! let mut errs = vec![]; +//! let nums: Vec<_> = vec!["17", "not a number", "99", "-27", "768"] +//! .into_iter() +//! .map(u8::from_str) +//! // Save clones of the raw `Result` values to inspect +//! .inspect(|x| results.push(x.clone())) +//! // Challenge: explain how this captures only the `Err` values +//! .inspect(|x| errs.extend(x.clone().err())) +//! .flatten() +//! .collect(); +//! assert_eq!(errs.len(), 3); +//! assert_eq!(nums, [17, 99]); +//! println!("results {:?}", results); +//! println!("errs {:?}", errs); +//! println!("nums {:?}", nums); +//! ``` +//! +//! ## Collecting into `Result` +//! +//! [`Result`] implements the [`FromIterator`][impl-FromIterator] trait, +//! which allows an iterator over [`Result`] values to be collected into a +//! [`Result`] of a collection of each contained value of the original +//! [`Result`] values, or [`Err`] if any of the elements was [`Err`]. +//! +//! [impl-FromIterator]: Result#impl-FromIterator%3CResult%3CA%2C%20E%3E%3E +//! +//! ``` +//! let v = vec![Ok(2), Ok(4), Err("err!"), Ok(8)]; +//! let res: Result<Vec<_>, &str> = v.into_iter().collect(); +//! assert_eq!(res, Err("err!")); +//! let v = vec![Ok(2), Ok(4), Ok(8)]; +//! let res: Result<Vec<_>, &str> = v.into_iter().collect(); +//! assert_eq!(res, Ok(vec![2, 4, 8])); +//! ``` +//! +//! [`Result`] also implements the [`Product`][impl-Product] and +//! [`Sum`][impl-Sum] traits, allowing an iterator over [`Result`] values +//! to provide the [`product`][Iterator::product] and +//! [`sum`][Iterator::sum] methods. +//! +//! [impl-Product]: Result#impl-Product%3CResult%3CU%2C%20E%3E%3E +//! [impl-Sum]: Result#impl-Sum%3CResult%3CU%2C%20E%3E%3E +//! +//! ``` +//! let v = vec![Err("error!"), Ok(1), Ok(2), Ok(3), Err("foo")]; +//! let res: Result<i32, &str> = v.into_iter().sum(); +//! assert_eq!(res, Err("error!")); +//! let v: Vec<Result<i32, &str>> = vec![Ok(1), Ok(2), Ok(21)]; +//! let res: Result<i32, &str> = v.into_iter().product(); +//! assert_eq!(res, Ok(42)); +//! ``` #![stable(feature = "rust1", since = "1.0.0")] @@ -1626,28 +1888,6 @@ impl<A, E, V: FromIterator<A>> FromIterator<Result<A, E>> for Result<V, E> { } } -#[unstable(feature = "try_trait", issue = "42327")] -#[cfg(bootstrap)] -impl<T, E> ops::TryV1 for Result<T, E> { - type Output = T; - type Error = E; - - #[inline] - fn into_result(self) -> Self { - self - } - - #[inline] - fn from_ok(v: T) -> Self { - Ok(v) - } - - #[inline] - fn from_error(v: E) -> Self { - Err(v) - } -} - #[unstable(feature = "try_trait_v2", issue = "84277")] impl<T, E> ops::TryV2 for Result<T, E> { type Output = T; diff --git a/library/core/src/slice/iter.rs b/library/core/src/slice/iter.rs index 1ee662c6c8e..c0dfba490ec 100644 --- a/library/core/src/slice/iter.rs +++ b/library/core/src/slice/iter.rs @@ -1,4 +1,3 @@ -// ignore-tidy-filelength //! Definitions of a bunch of iterators for `[T]`. #[macro_use] // import iterator! and forward_iterator! @@ -8,7 +7,7 @@ use crate::cmp; use crate::cmp::Ordering; use crate::fmt; use crate::intrinsics::{assume, exact_div, unchecked_sub}; -use crate::iter::{FusedIterator, TrustedLen, TrustedRandomAccess}; +use crate::iter::{FusedIterator, TrustedLen, TrustedRandomAccess, TrustedRandomAccessNoCoerce}; use crate::marker::{PhantomData, Send, Sized, Sync}; use crate::mem; use crate::num::NonZeroUsize; @@ -401,7 +400,13 @@ where #[inline] fn size_hint(&self) -> (usize, Option<usize>) { - if self.finished { (0, Some(0)) } else { (1, Some(self.v.len() + 1)) } + if self.finished { + (0, Some(0)) + } else { + // If the predicate doesn't match anything, we yield one slice. + // If it matches every element, we yield `len() + 1` empty slices. + (1, Some(self.v.len() + 1)) + } } } @@ -526,7 +531,14 @@ where #[inline] fn size_hint(&self) -> (usize, Option<usize>) { - if self.finished { (0, Some(0)) } else { (1, Some(self.v.len() + 1)) } + if self.finished { + (0, Some(0)) + } else { + // If the predicate doesn't match anything, we yield one slice. + // If it matches every element, we yield `len()` one-element slices, + // or a single empty slice. + (1, Some(cmp::max(1, self.v.len()))) + } } } @@ -648,8 +660,8 @@ where if self.finished { (0, Some(0)) } else { - // if the predicate doesn't match anything, we yield one slice - // if it matches every element, we yield len+1 empty slices. + // If the predicate doesn't match anything, we yield one slice. + // If it matches every element, we yield `len() + 1` empty slices. (1, Some(self.v.len() + 1)) } } @@ -764,9 +776,10 @@ where if self.finished { (0, Some(0)) } else { - // if the predicate doesn't match anything, we yield one slice - // if it matches every element, we yield len+1 empty slices. - (1, Some(self.v.len() + 1)) + // If the predicate doesn't match anything, we yield one slice. + // If it matches every element, we yield `len()` one-element slices, + // or a single empty slice. + (1, Some(cmp::max(1, self.v.len()))) } } } @@ -1009,7 +1022,10 @@ impl<T, I: SplitIter<Item = T>> Iterator for GenericSplitN<I> { #[inline] fn size_hint(&self) -> (usize, Option<usize>) { let (lower, upper_opt) = self.iter.size_hint(); - (lower, upper_opt.map(|upper| cmp::min(self.count, upper))) + ( + cmp::min(self.count, lower), + Some(upper_opt.map_or(self.count, |upper| cmp::min(self.count, upper))), + ) } } @@ -1312,7 +1328,11 @@ impl<T> FusedIterator for Windows<'_, T> {} #[doc(hidden)] #[unstable(feature = "trusted_random_access", issue = "none")] -unsafe impl<'a, T> TrustedRandomAccess for Windows<'a, T> { +unsafe impl<'a, T> TrustedRandomAccess for Windows<'a, T> {} + +#[doc(hidden)] +#[unstable(feature = "trusted_random_access", issue = "none")] +unsafe impl<'a, T> TrustedRandomAccessNoCoerce for Windows<'a, T> { const MAY_HAVE_SIDE_EFFECT: bool = false; } @@ -1418,18 +1438,17 @@ impl<'a, T> Iterator for Chunks<'a, T> { #[doc(hidden)] unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item { let start = idx * self.chunk_size; - let end = match start.checked_add(self.chunk_size) { - None => self.v.len(), - Some(end) => cmp::min(end, self.v.len()), - }; // SAFETY: the caller guarantees that `i` is in bounds, // which means that `start` must be in bounds of the - // underlying `self.v` slice, and we made sure that `end` + // underlying `self.v` slice, and we made sure that `len` // is also in bounds of `self.v`. Thus, `start` cannot overflow // an `isize`, and the slice constructed by `from_raw_parts` // is a subslice of `self.v` which is guaranteed to be valid // for the lifetime `'a` of `self.v`. - unsafe { from_raw_parts(self.v.as_ptr().add(start), end - start) } + unsafe { + let len = cmp::min(self.v.len().unchecked_sub(start), self.chunk_size); + from_raw_parts(self.v.as_ptr().add(start), len) + } } } @@ -1457,7 +1476,7 @@ impl<'a, T> DoubleEndedIterator for Chunks<'a, T> { } else { let start = (len - 1 - n) * self.chunk_size; let end = match start.checked_add(self.chunk_size) { - Some(res) => cmp::min(res, self.v.len()), + Some(res) => cmp::min(self.v.len(), res), None => self.v.len(), }; let nth_back = &self.v[start..end]; @@ -1478,7 +1497,11 @@ impl<T> FusedIterator for Chunks<'_, T> {} #[doc(hidden)] #[unstable(feature = "trusted_random_access", issue = "none")] -unsafe impl<'a, T> TrustedRandomAccess for Chunks<'a, T> { +unsafe impl<'a, T> TrustedRandomAccess for Chunks<'a, T> {} + +#[doc(hidden)] +#[unstable(feature = "trusted_random_access", issue = "none")] +unsafe impl<'a, T> TrustedRandomAccessNoCoerce for Chunks<'a, T> { const MAY_HAVE_SIDE_EFFECT: bool = false; } @@ -1579,17 +1602,16 @@ impl<'a, T> Iterator for ChunksMut<'a, T> { #[doc(hidden)] unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item { let start = idx * self.chunk_size; - let end = match start.checked_add(self.chunk_size) { - None => self.v.len(), - Some(end) => cmp::min(end, self.v.len()), - }; // SAFETY: see comments for `Chunks::__iterator_get_unchecked`. // // Also note that the caller also guarantees that we're never called // with the same index again, and that no other methods that will // access this subslice are called, so it is valid for the returned // slice to be mutable. - unsafe { from_raw_parts_mut(self.v.as_mut_ptr().add(start), end - start) } + unsafe { + let len = cmp::min(self.v.len().unchecked_sub(start), self.chunk_size); + from_raw_parts_mut(self.v.as_mut_ptr().add(start), len) + } } } @@ -1619,7 +1641,7 @@ impl<'a, T> DoubleEndedIterator for ChunksMut<'a, T> { } else { let start = (len - 1 - n) * self.chunk_size; let end = match start.checked_add(self.chunk_size) { - Some(res) => cmp::min(res, self.v.len()), + Some(res) => cmp::min(self.v.len(), res), None => self.v.len(), }; let (temp, _tail) = mem::replace(&mut self.v, &mut []).split_at_mut(end); @@ -1641,7 +1663,11 @@ impl<T> FusedIterator for ChunksMut<'_, T> {} #[doc(hidden)] #[unstable(feature = "trusted_random_access", issue = "none")] -unsafe impl<'a, T> TrustedRandomAccess for ChunksMut<'a, T> { +unsafe impl<'a, T> TrustedRandomAccess for ChunksMut<'a, T> {} + +#[doc(hidden)] +#[unstable(feature = "trusted_random_access", issue = "none")] +unsafe impl<'a, T> TrustedRandomAccessNoCoerce for ChunksMut<'a, T> { const MAY_HAVE_SIDE_EFFECT: bool = false; } @@ -1795,7 +1821,11 @@ impl<T> FusedIterator for ChunksExact<'_, T> {} #[doc(hidden)] #[unstable(feature = "trusted_random_access", issue = "none")] -unsafe impl<'a, T> TrustedRandomAccess for ChunksExact<'a, T> { +unsafe impl<'a, T> TrustedRandomAccess for ChunksExact<'a, T> {} + +#[doc(hidden)] +#[unstable(feature = "trusted_random_access", issue = "none")] +unsafe impl<'a, T> TrustedRandomAccessNoCoerce for ChunksExact<'a, T> { const MAY_HAVE_SIDE_EFFECT: bool = false; } @@ -1946,7 +1976,11 @@ impl<T> FusedIterator for ChunksExactMut<'_, T> {} #[doc(hidden)] #[unstable(feature = "trusted_random_access", issue = "none")] -unsafe impl<'a, T> TrustedRandomAccess for ChunksExactMut<'a, T> { +unsafe impl<'a, T> TrustedRandomAccess for ChunksExactMut<'a, T> {} + +#[doc(hidden)] +#[unstable(feature = "trusted_random_access", issue = "none")] +unsafe impl<'a, T> TrustedRandomAccessNoCoerce for ChunksExactMut<'a, T> { const MAY_HAVE_SIDE_EFFECT: bool = false; } @@ -2148,6 +2182,7 @@ impl<'a, T, const N: usize> Iterator for ArrayChunks<'a, T, N> { self.iter.last() } + #[doc(hidden)] unsafe fn __iterator_get_unchecked(&mut self, i: usize) -> &'a [T; N] { // SAFETY: The safety guarantees of `__iterator_get_unchecked` are // transferred to the caller. @@ -2183,7 +2218,11 @@ impl<T, const N: usize> FusedIterator for ArrayChunks<'_, T, N> {} #[doc(hidden)] #[unstable(feature = "array_chunks", issue = "74985")] -unsafe impl<'a, T, const N: usize> TrustedRandomAccess for ArrayChunks<'a, T, N> { +unsafe impl<'a, T, const N: usize> TrustedRandomAccess for ArrayChunks<'a, T, N> {} + +#[doc(hidden)] +#[unstable(feature = "array_chunks", issue = "74985")] +unsafe impl<'a, T, const N: usize> TrustedRandomAccessNoCoerce for ArrayChunks<'a, T, N> { const MAY_HAVE_SIDE_EFFECT: bool = false; } @@ -2260,6 +2299,7 @@ impl<'a, T, const N: usize> Iterator for ArrayChunksMut<'a, T, N> { self.iter.last() } + #[doc(hidden)] unsafe fn __iterator_get_unchecked(&mut self, i: usize) -> &'a mut [T; N] { // SAFETY: The safety guarantees of `__iterator_get_unchecked` are transferred to // the caller. @@ -2295,7 +2335,11 @@ impl<T, const N: usize> FusedIterator for ArrayChunksMut<'_, T, N> {} #[doc(hidden)] #[unstable(feature = "array_chunks", issue = "74985")] -unsafe impl<'a, T, const N: usize> TrustedRandomAccess for ArrayChunksMut<'a, T, N> { +unsafe impl<'a, T, const N: usize> TrustedRandomAccess for ArrayChunksMut<'a, T, N> {} + +#[doc(hidden)] +#[unstable(feature = "array_chunks", issue = "74985")] +unsafe impl<'a, T, const N: usize> TrustedRandomAccessNoCoerce for ArrayChunksMut<'a, T, N> { const MAY_HAVE_SIDE_EFFECT: bool = false; } @@ -2457,7 +2501,11 @@ impl<T> FusedIterator for RChunks<'_, T> {} #[doc(hidden)] #[unstable(feature = "trusted_random_access", issue = "none")] -unsafe impl<'a, T> TrustedRandomAccess for RChunks<'a, T> { +unsafe impl<'a, T> TrustedRandomAccess for RChunks<'a, T> {} + +#[doc(hidden)] +#[unstable(feature = "trusted_random_access", issue = "none")] +unsafe impl<'a, T> TrustedRandomAccessNoCoerce for RChunks<'a, T> { const MAY_HAVE_SIDE_EFFECT: bool = false; } @@ -2618,7 +2666,11 @@ impl<T> FusedIterator for RChunksMut<'_, T> {} #[doc(hidden)] #[unstable(feature = "trusted_random_access", issue = "none")] -unsafe impl<'a, T> TrustedRandomAccess for RChunksMut<'a, T> { +unsafe impl<'a, T> TrustedRandomAccess for RChunksMut<'a, T> {} + +#[doc(hidden)] +#[unstable(feature = "trusted_random_access", issue = "none")] +unsafe impl<'a, T> TrustedRandomAccessNoCoerce for RChunksMut<'a, T> { const MAY_HAVE_SIDE_EFFECT: bool = false; } @@ -2776,7 +2828,11 @@ impl<T> FusedIterator for RChunksExact<'_, T> {} #[doc(hidden)] #[unstable(feature = "trusted_random_access", issue = "none")] -unsafe impl<'a, T> TrustedRandomAccess for RChunksExact<'a, T> { +unsafe impl<'a, T> TrustedRandomAccess for RChunksExact<'a, T> {} + +#[doc(hidden)] +#[unstable(feature = "trusted_random_access", issue = "none")] +unsafe impl<'a, T> TrustedRandomAccessNoCoerce for RChunksExact<'a, T> { const MAY_HAVE_SIDE_EFFECT: bool = false; } @@ -2931,19 +2987,31 @@ impl<T> FusedIterator for RChunksExactMut<'_, T> {} #[doc(hidden)] #[unstable(feature = "trusted_random_access", issue = "none")] -unsafe impl<'a, T> TrustedRandomAccess for RChunksExactMut<'a, T> { +unsafe impl<'a, T> TrustedRandomAccess for RChunksExactMut<'a, T> {} + +#[doc(hidden)] +#[unstable(feature = "trusted_random_access", issue = "none")] +unsafe impl<'a, T> TrustedRandomAccessNoCoerce for RChunksExactMut<'a, T> { const MAY_HAVE_SIDE_EFFECT: bool = false; } #[doc(hidden)] #[unstable(feature = "trusted_random_access", issue = "none")] -unsafe impl<'a, T> TrustedRandomAccess for Iter<'a, T> { +unsafe impl<'a, T> TrustedRandomAccess for Iter<'a, T> {} + +#[doc(hidden)] +#[unstable(feature = "trusted_random_access", issue = "none")] +unsafe impl<'a, T> TrustedRandomAccessNoCoerce for Iter<'a, T> { const MAY_HAVE_SIDE_EFFECT: bool = false; } #[doc(hidden)] #[unstable(feature = "trusted_random_access", issue = "none")] -unsafe impl<'a, T> TrustedRandomAccess for IterMut<'a, T> { +unsafe impl<'a, T> TrustedRandomAccess for IterMut<'a, T> {} + +#[doc(hidden)] +#[unstable(feature = "trusted_random_access", issue = "none")] +unsafe impl<'a, T> TrustedRandomAccessNoCoerce for IterMut<'a, T> { const MAY_HAVE_SIDE_EFFECT: bool = false; } diff --git a/library/core/src/slice/iter/macros.rs b/library/core/src/slice/iter/macros.rs index 457b2a3605e..cf15756868e 100644 --- a/library/core/src/slice/iter/macros.rs +++ b/library/core/src/slice/iter/macros.rs @@ -186,6 +186,14 @@ macro_rules! iterator { } #[inline] + fn advance_by(&mut self, n: usize) -> Result<(), usize> { + let advance = cmp::min(len!(self), n); + // SAFETY: By construction, `advance` does not exceed `self.len()`. + unsafe { self.post_inc_start(advance as isize) }; + if advance == n { Ok(()) } else { Err(advance) } + } + + #[inline] fn last(mut self) -> Option<$elem> { self.next_back() } @@ -371,6 +379,14 @@ macro_rules! iterator { Some(next_back_unchecked!(self)) } } + + #[inline] + fn advance_back_by(&mut self, n: usize) -> Result<(), usize> { + let advance = cmp::min(len!(self), n); + // SAFETY: By construction, `advance` does not exceed `self.len()`. + unsafe { self.pre_dec_end(advance as isize) }; + if advance == n { Ok(()) } else { Err(advance) } + } } #[stable(feature = "fused", since = "1.26.0")] diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 3bcea4e6d25..361a9b03aeb 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -1,5 +1,3 @@ -// ignore-tidy-filelength - //! Slice management and manipulation. //! //! For more details see [`std::slice`]. @@ -95,12 +93,12 @@ impl<T> [T] { /// let a = [1, 2, 3]; /// assert_eq!(a.len(), 3); /// ``` - #[doc(alias = "length")] + #[lang = "slice_len_fn"] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_slice_len", since = "1.39.0")] #[inline] // SAFETY: const sound because we transmute out the length field as a usize (which it must be) - #[rustc_allow_const_fn_unstable(const_fn_union)] + #[cfg_attr(bootstrap, rustc_allow_const_fn_unstable(const_fn_union))] pub const fn len(&self) -> usize { // FIXME: Replace with `crate::ptr::metadata(self)` when that is const-stable. // As of this writing this causes a "Const-stable functions can only call other @@ -139,7 +137,7 @@ impl<T> [T] { /// assert_eq!(None, w.first()); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_slice_first_last", issue = "83570")] + #[rustc_const_stable(feature = "const_slice_first_last_not_mut", since = "1.56.0")] #[inline] pub const fn first(&self) -> Option<&T> { if let [first, ..] = self { Some(first) } else { None } @@ -177,7 +175,7 @@ impl<T> [T] { /// } /// ``` #[stable(feature = "slice_splits", since = "1.5.0")] - #[rustc_const_unstable(feature = "const_slice_first_last", issue = "83570")] + #[rustc_const_stable(feature = "const_slice_first_last_not_mut", since = "1.56.0")] #[inline] pub const fn split_first(&self) -> Option<(&T, &[T])> { if let [first, tail @ ..] = self { Some((first, tail)) } else { None } @@ -217,7 +215,7 @@ impl<T> [T] { /// } /// ``` #[stable(feature = "slice_splits", since = "1.5.0")] - #[rustc_const_unstable(feature = "const_slice_first_last", issue = "83570")] + #[rustc_const_stable(feature = "const_slice_first_last_not_mut", since = "1.56.0")] #[inline] pub const fn split_last(&self) -> Option<(&T, &[T])> { if let [init @ .., last] = self { Some((last, init)) } else { None } @@ -256,7 +254,7 @@ impl<T> [T] { /// assert_eq!(None, w.last()); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_slice_first_last", issue = "83570")] + #[rustc_const_stable(feature = "const_slice_first_last_not_mut", since = "1.56.0")] #[inline] pub const fn last(&self) -> Option<&T> { if let [.., last] = self { Some(last) } else { None } @@ -2100,9 +2098,11 @@ impl<T> [T] { /// /// If the value is found then [`Result::Ok`] is returned, containing the /// index of the matching element. If there are multiple matches, then any - /// one of the matches could be returned. If the value is not found then - /// [`Result::Err`] is returned, containing the index where a matching - /// element could be inserted while maintaining sorted order. + /// one of the matches could be returned. The index is chosen + /// deterministically, but is subject to change in future versions of Rust. + /// If the value is not found then [`Result::Err`] is returned, containing + /// the index where a matching element could be inserted while maintaining + /// sorted order. /// /// See also [`binary_search_by`], [`binary_search_by_key`], and [`partition_point`]. /// @@ -2153,9 +2153,11 @@ impl<T> [T] { /// /// If the value is found then [`Result::Ok`] is returned, containing the /// index of the matching element. If there are multiple matches, then any - /// one of the matches could be returned. If the value is not found then - /// [`Result::Err`] is returned, containing the index where a matching - /// element could be inserted while maintaining sorted order. + /// one of the matches could be returned. The index is chosen + /// deterministically, but is subject to change in future versions of Rust. + /// If the value is not found then [`Result::Err`] is returned, containing + /// the index where a matching element could be inserted while maintaining + /// sorted order. /// /// See also [`binary_search`], [`binary_search_by_key`], and [`partition_point`]. /// @@ -2224,9 +2226,11 @@ impl<T> [T] { /// /// If the value is found then [`Result::Ok`] is returned, containing the /// index of the matching element. If there are multiple matches, then any - /// one of the matches could be returned. If the value is not found then - /// [`Result::Err`] is returned, containing the index where a matching - /// element could be inserted while maintaining sorted order. + /// one of the matches could be returned. The index is chosen + /// deterministically, but is subject to change in future versions of Rust. + /// If the value is not found then [`Result::Err`] is returned, containing + /// the index where a matching element could be inserted while maintaining + /// sorted order. /// /// See also [`binary_search`], [`binary_search_by`], and [`partition_point`]. /// @@ -2268,7 +2272,7 @@ impl<T> [T] { self.binary_search_by(|k| f(k).cmp(b)) } - /// Sorts the slice, but may not preserve the order of equal elements. + /// Sorts the slice, but might not preserve the order of equal elements. /// /// This sort is unstable (i.e., may reorder equal elements), in-place /// (i.e., does not allocate), and *O*(*n* \* log(*n*)) worst-case. @@ -2303,7 +2307,7 @@ impl<T> [T] { sort::quicksort(self, |a, b| a.lt(b)); } - /// Sorts the slice with a comparator function, but may not preserve the order of equal + /// Sorts the slice with a comparator function, but might not preserve the order of equal /// elements. /// /// This sort is unstable (i.e., may reorder equal elements), in-place @@ -2358,7 +2362,7 @@ impl<T> [T] { sort::quicksort(self, |a, b| compare(a, b) == Ordering::Less); } - /// Sorts the slice with a key extraction function, but may not preserve the order of equal + /// Sorts the slice with a key extraction function, but might not preserve the order of equal /// elements. /// /// This sort is unstable (i.e., may reorder equal elements), in-place @@ -3462,27 +3466,7 @@ impl<T> [T] { where P: FnMut(&T) -> bool, { - let mut left = 0; - let mut right = self.len(); - - while left != right { - let mid = left + (right - left) / 2; - // SAFETY: When `left < right`, `left <= mid < right`. - // Therefore `left` always increases and `right` always decreases, - // and either of them is selected. In both cases `left <= right` is - // satisfied. Therefore if `left < right` in a step, `left <= right` - // is satisfied in the next step. Therefore as long as `left != right`, - // `0 <= left < right <= len` is satisfied and if this case - // `0 <= mid < len` is satisfied too. - let value = unsafe { self.get_unchecked(mid) }; - if pred(value) { - left = mid + 1; - } else { - right = mid; - } - } - - left + self.binary_search_by(|x| if pred(x) { Less } else { Greater }).unwrap_or_else(|i| i) } } @@ -3517,7 +3501,8 @@ where } #[stable(feature = "rust1", since = "1.0.0")] -impl<T> Default for &[T] { +#[rustc_const_unstable(feature = "const_default_impls", issue = "87864")] +impl<T> const Default for &[T] { /// Creates an empty slice. fn default() -> Self { &[] @@ -3525,7 +3510,8 @@ impl<T> Default for &[T] { } #[stable(feature = "mut_slice_default", since = "1.5.0")] -impl<T> Default for &mut [T] { +#[rustc_const_unstable(feature = "const_default_impls", issue = "87864")] +impl<T> const Default for &mut [T] { /// Creates a mutable empty slice. fn default() -> Self { &mut [] diff --git a/library/core/src/slice/rotate.rs b/library/core/src/slice/rotate.rs index a89596b15ef..7528927ef33 100644 --- a/library/core/src/slice/rotate.rs +++ b/library/core/src/slice/rotate.rs @@ -1,5 +1,3 @@ -// ignore-tidy-undocumented-unsafe - use crate::cmp; use crate::mem::{self, MaybeUninit}; use crate::ptr; @@ -79,8 +77,10 @@ pub unsafe fn ptr_rotate<T>(mut left: usize, mut mid: *mut T, mut right: usize) // the way until about `left + right == 32`, but the worst case performance breaks even // around 16. 24 was chosen as middle ground. If the size of `T` is larger than 4 // `usize`s, this algorithm also outperforms other algorithms. + // SAFETY: callers must ensure `mid - left` is valid for reading and writing. let x = unsafe { mid.sub(left) }; // beginning of first round + // SAFETY: see previous comment. let mut tmp: T = unsafe { x.read() }; let mut i = right; // `gcd` can be found before hand by calculating `gcd(left + right, right)`, @@ -92,6 +92,21 @@ pub unsafe fn ptr_rotate<T>(mut left: usize, mut mid: *mut T, mut right: usize) // the very end. This is possibly due to the fact that swapping or replacing temporaries // uses only one memory address in the loop instead of needing to manage two. loop { + // [long-safety-expl] + // SAFETY: callers must ensure `[left, left+mid+right)` are all valid for reading and + // writing. + // + // - `i` start with `right` so `mid-left <= x+i = x+right = mid-left+right < mid+right` + // - `i <= left+right-1` is always true + // - if `i < left`, `right` is added so `i < left+right` and on the next + // iteration `left` is removed from `i` so it doesn't go further + // - if `i >= left`, `left` is removed immediately and so it doesn't go further. + // - overflows cannot happen for `i` since the function's safety contract ask for + // `mid+right-1 = x+left+right` to be valid for writing + // - underflows cannot happen because `i` must be bigger or equal to `left` for + // a substraction of `left` to happen. + // + // So `x+i` is valid for reading and writing if the caller respected the contract tmp = unsafe { x.add(i).replace(tmp) }; // instead of incrementing `i` and then checking if it is outside the bounds, we // check if `i` will go outside the bounds on the next increment. This prevents @@ -100,6 +115,8 @@ pub unsafe fn ptr_rotate<T>(mut left: usize, mut mid: *mut T, mut right: usize) i -= left; if i == 0 { // end of first round + // SAFETY: tmp has been read from a valid source and x is valid for writing + // according to the caller. unsafe { x.write(tmp) }; break; } @@ -113,13 +130,24 @@ pub unsafe fn ptr_rotate<T>(mut left: usize, mut mid: *mut T, mut right: usize) } // finish the chunk with more rounds for start in 1..gcd { + // SAFETY: `gcd` is at most equal to `right` so all values in `1..gcd` are valid for + // reading and writing as per the function's safety contract, see [long-safety-expl] + // above tmp = unsafe { x.add(start).read() }; + // [safety-expl-addition] + // + // Here `start < gcd` so `start < right` so `i < right+right`: `right` being the + // greatest common divisor of `(left+right, right)` means that `left = right` so + // `i < left+right` so `x+i = mid-left+i` is always valid for reading and writing + // according to the function's safety contract. i = start + right; loop { + // SAFETY: see [long-safety-expl] and [safety-expl-addition] tmp = unsafe { x.add(i).replace(tmp) }; if i >= left { i -= left; if i == start { + // SAFETY: see [long-safety-expl] and [safety-expl-addition] unsafe { x.add(start).write(tmp) }; break; } @@ -135,14 +163,30 @@ pub unsafe fn ptr_rotate<T>(mut left: usize, mut mid: *mut T, mut right: usize) // The `[T; 0]` here is to ensure this is appropriately aligned for T let mut rawarray = MaybeUninit::<(BufType, [T; 0])>::uninit(); let buf = rawarray.as_mut_ptr() as *mut T; + // SAFETY: `mid-left <= mid-left+right < mid+right` let dim = unsafe { mid.sub(left).add(right) }; if left <= right { + // SAFETY: + // + // 1) The `else if` condition about the sizes ensures `[mid-left; left]` will fit in + // `buf` without overflow and `buf` was created just above and so cannot be + // overlapped with any value of `[mid-left; left]` + // 2) [mid-left, mid+right) are all valid for reading and writing and we don't care + // about overlaps here. + // 3) The `if` condition about `left <= right` ensures writing `left` elements to + // `dim = mid-left+right` is valid because: + // - `buf` is valid and `left` elements were written in it in 1) + // - `dim+left = mid-left+right+left = mid+right` and we write `[dim, dim+left)` unsafe { + // 1) ptr::copy_nonoverlapping(mid.sub(left), buf, left); + // 2) ptr::copy(mid, mid.sub(left), right); + // 3) ptr::copy_nonoverlapping(buf, dim, left); } } else { + // SAFETY: same reasoning as above but with `left` and `right` reversed unsafe { ptr::copy_nonoverlapping(mid, buf, right); ptr::copy(mid.sub(left), dim, left); @@ -156,6 +200,10 @@ pub unsafe fn ptr_rotate<T>(mut left: usize, mut mid: *mut T, mut right: usize) // of this algorithm would be, and swapping using that last chunk instead of swapping // adjacent chunks like this algorithm is doing, but this way is still faster. loop { + // SAFETY: + // `left >= right` so `[mid-right, mid+right)` is valid for reading and writing + // Substracting `right` from `mid` each turn is counterbalanced by the addition and + // check after it. unsafe { ptr::swap_nonoverlapping(mid.sub(right), mid, right); mid = mid.sub(right); @@ -168,6 +216,10 @@ pub unsafe fn ptr_rotate<T>(mut left: usize, mut mid: *mut T, mut right: usize) } else { // Algorithm 3, `left < right` loop { + // SAFETY: `[mid-left, mid+left)` is valid for reading and writing because + // `left < right` so `mid+left < mid+right`. + // Adding `left` to `mid` each turn is counterbalanced by the substraction and check + // after it. unsafe { ptr::swap_nonoverlapping(mid.sub(left), mid, left); mid = mid.add(left); diff --git a/library/core/src/slice/sort.rs b/library/core/src/slice/sort.rs index 2a7693d27ef..36c2c4abdb4 100644 --- a/library/core/src/slice/sort.rs +++ b/library/core/src/slice/sort.rs @@ -227,7 +227,7 @@ where /// Partitioning is performed block-by-block in order to minimize the cost of branching operations. /// This idea is presented in the [BlockQuicksort][pdf] paper. /// -/// [pdf]: http://drops.dagstuhl.de/opus/volltexte/2016/6389/pdf/LIPIcs-ESA-2016-38.pdf +/// [pdf]: https://drops.dagstuhl.de/opus/volltexte/2016/6389/pdf/LIPIcs-ESA-2016-38.pdf fn partition_in_blocks<T, F>(v: &mut [T], pivot: &T, is_less: &mut F) -> usize where F: FnMut(&T, &T) -> bool, diff --git a/library/core/src/slice/specialize.rs b/library/core/src/slice/specialize.rs index 425cf71626f..80eb590587f 100644 --- a/library/core/src/slice/specialize.rs +++ b/library/core/src/slice/specialize.rs @@ -1,6 +1,3 @@ -use crate::mem::{size_of, transmute_copy}; -use crate::ptr::write_bytes; - pub(super) trait SpecFill<T> { fn spec_fill(&mut self, value: T); } @@ -19,17 +16,8 @@ impl<T: Clone> SpecFill<T> for [T] { impl<T: Copy> SpecFill<T> for [T] { fn spec_fill(&mut self, value: T) { - if size_of::<T>() == 1 { - // SAFETY: The size_of check above ensures that values are 1 byte wide, as required - // for the transmute and write_bytes - unsafe { - let value: u8 = transmute_copy(&value); - write_bytes(self.as_mut_ptr(), value, self.len()); - } - } else { - for item in self.iter_mut() { - *item = value; - } + for item in self.iter_mut() { + *item = value; } } } diff --git a/library/core/src/str/converts.rs b/library/core/src/str/converts.rs index 05ff7bb120d..e67c0d6487c 100644 --- a/library/core/src/str/converts.rs +++ b/library/core/src/str/converts.rs @@ -156,8 +156,8 @@ pub fn from_utf8_mut(v: &mut [u8]) -> Result<&mut str, Utf8Error> { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_const_unstable(feature = "const_str_from_utf8_unchecked", issue = "75196")] -#[rustc_allow_const_fn_unstable(const_fn_transmute)] +#[rustc_const_stable(feature = "const_str_from_utf8_unchecked", since = "1.55.0")] +#[cfg_attr(bootstrap, rustc_allow_const_fn_unstable(const_fn_transmute))] pub const unsafe fn from_utf8_unchecked(v: &[u8]) -> &str { // SAFETY: the caller must guarantee that the bytes `v` are valid UTF-8. // Also relies on `&str` and `&[u8]` having the same layout. diff --git a/library/core/src/str/error.rs b/library/core/src/str/error.rs index ccf7b20285c..aa735a14cbd 100644 --- a/library/core/src/str/error.rs +++ b/library/core/src/str/error.rs @@ -118,10 +118,9 @@ impl fmt::Display for Utf8Error { /// /// [`from_str`]: super::FromStr::from_str #[derive(Debug, Clone, PartialEq, Eq)] +#[non_exhaustive] #[stable(feature = "rust1", since = "1.0.0")] -pub struct ParseBoolError { - pub(super) _priv: (), -} +pub struct ParseBoolError; #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Display for ParseBoolError { diff --git a/library/core/src/str/iter.rs b/library/core/src/str/iter.rs index 6ec6b70b571..8db9edc6147 100644 --- a/library/core/src/str/iter.rs +++ b/library/core/src/str/iter.rs @@ -2,9 +2,9 @@ use crate::char; use crate::fmt::{self, Write}; -use crate::iter::TrustedRandomAccess; use crate::iter::{Chain, FlatMap, Flatten}; use crate::iter::{Copied, Filter, FusedIterator, Map, TrustedLen}; +use crate::iter::{TrustedRandomAccess, TrustedRandomAccessNoCoerce}; use crate::ops::Try; use crate::option; use crate::slice::{self, Split as SliceSplit}; @@ -295,6 +295,7 @@ impl Iterator for Bytes<'_> { } #[inline] + #[doc(hidden)] unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> u8 { // SAFETY: the caller must uphold the safety contract // for `Iterator::__iterator_get_unchecked`. @@ -344,7 +345,11 @@ unsafe impl TrustedLen for Bytes<'_> {} #[doc(hidden)] #[unstable(feature = "trusted_random_access", issue = "none")] -unsafe impl TrustedRandomAccess for Bytes<'_> { +unsafe impl TrustedRandomAccess for Bytes<'_> {} + +#[doc(hidden)] +#[unstable(feature = "trusted_random_access", issue = "none")] +unsafe impl TrustedRandomAccessNoCoerce for Bytes<'_> { const MAY_HAVE_SIDE_EFFECT: bool = false; } diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs index 065acd3f38b..947afbdc68d 100644 --- a/library/core/src/str/mod.rs +++ b/library/core/src/str/mod.rs @@ -123,7 +123,7 @@ impl str { /// Returns the length of `self`. /// /// This length is in bytes, not [`char`]s or graphemes. In other words, - /// it may not be what a human considers the length of the string. + /// it might not be what a human considers the length of the string. /// /// [`char`]: prim@char /// @@ -138,7 +138,6 @@ impl str { /// assert_eq!("ƒoo".len(), 4); // fancy f! /// assert_eq!("ƒoo".chars().count(), 3); /// ``` - #[doc(alias = "length")] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_str_len", since = "1.39.0")] #[inline] @@ -232,7 +231,7 @@ impl str { #[rustc_const_stable(feature = "str_as_bytes", since = "1.39.0")] #[inline(always)] #[allow(unused_attributes)] - #[rustc_allow_const_fn_unstable(const_fn_transmute)] + #[cfg_attr(bootstrap, rustc_allow_const_fn_unstable(const_fn_transmute))] pub const fn as_bytes(&self) -> &[u8] { // SAFETY: const sound because we transmute two types with the same layout unsafe { mem::transmute(self) } @@ -634,7 +633,7 @@ impl str { /// string slice by [`char`]. This method returns such an iterator. /// /// It's important to remember that [`char`] represents a Unicode Scalar - /// Value, and may not match your idea of what a 'character' is. Iteration + /// Value, and might not match your idea of what a 'character' is. Iteration /// over grapheme clusters may be what you actually want. This functionality /// is not provided by Rust's standard library, check crates.io instead. /// @@ -661,7 +660,7 @@ impl str { /// assert_eq!(None, chars.next()); /// ``` /// - /// Remember, [`char`]s may not match your intuition about characters: + /// Remember, [`char`]s might not match your intuition about characters: /// /// [`char`]: prim@char /// @@ -714,7 +713,7 @@ impl str { /// assert_eq!(None, char_indices.next()); /// ``` /// - /// Remember, [`char`]s may not match your intuition about characters: + /// Remember, [`char`]s might not match your intuition about characters: /// /// [`char`]: prim@char /// @@ -2443,7 +2442,8 @@ impl AsRef<[u8]> for str { } #[stable(feature = "rust1", since = "1.0.0")] -impl Default for &str { +#[rustc_const_unstable(feature = "const_default_impls", issue = "87864")] +impl const Default for &str { /// Creates an empty str #[inline] fn default() -> Self { diff --git a/library/core/src/str/pattern.rs b/library/core/src/str/pattern.rs index 508c522e71a..55ac1aa765c 100644 --- a/library/core/src/str/pattern.rs +++ b/library/core/src/str/pattern.rs @@ -928,6 +928,8 @@ struct EmptyNeedle { end: usize, is_match_fw: bool, is_match_bw: bool, + // Needed in case of an empty haystack, see #85462 + is_finished: bool, } impl<'a, 'b> StrSearcher<'a, 'b> { @@ -941,6 +943,7 @@ impl<'a, 'b> StrSearcher<'a, 'b> { end: haystack.len(), is_match_fw: true, is_match_bw: true, + is_finished: false, }), } } else { @@ -966,13 +969,19 @@ unsafe impl<'a, 'b> Searcher<'a> for StrSearcher<'a, 'b> { fn next(&mut self) -> SearchStep { match self.searcher { StrSearcherImpl::Empty(ref mut searcher) => { + if searcher.is_finished { + return SearchStep::Done; + } // empty needle rejects every char and matches every empty string between them let is_match = searcher.is_match_fw; searcher.is_match_fw = !searcher.is_match_fw; let pos = searcher.position; match self.haystack[pos..].chars().next() { _ if is_match => SearchStep::Match(pos, pos), - None => SearchStep::Done, + None => { + searcher.is_finished = true; + SearchStep::Done + } Some(ch) => { searcher.position += ch.len_utf8(); SearchStep::Reject(pos, searcher.position) @@ -1045,12 +1054,18 @@ unsafe impl<'a, 'b> ReverseSearcher<'a> for StrSearcher<'a, 'b> { fn next_back(&mut self) -> SearchStep { match self.searcher { StrSearcherImpl::Empty(ref mut searcher) => { + if searcher.is_finished { + return SearchStep::Done; + } let is_match = searcher.is_match_bw; searcher.is_match_bw = !searcher.is_match_bw; let end = searcher.end; match self.haystack[..end].chars().next_back() { _ if is_match => SearchStep::Match(end, end), - None => SearchStep::Done, + None => { + searcher.is_finished = true; + SearchStep::Done + } Some(ch) => { searcher.end -= ch.len_utf8(); SearchStep::Reject(searcher.end, end) diff --git a/library/core/src/str/traits.rs b/library/core/src/str/traits.rs index 0a2743b1c31..12d79a56a52 100644 --- a/library/core/src/str/traits.rs +++ b/library/core/src/str/traits.rs @@ -585,7 +585,7 @@ impl FromStr for bool { match s { "true" => Ok(true), "false" => Ok(false), - _ => Err(ParseBoolError { _priv: () }), + _ => Err(ParseBoolError), } } } diff --git a/library/core/src/stream/from_iter.rs b/library/core/src/stream/from_iter.rs new file mode 100644 index 00000000000..eb9a0fd2842 --- /dev/null +++ b/library/core/src/stream/from_iter.rs @@ -0,0 +1,38 @@ +use crate::pin::Pin; + +use crate::stream::Stream; +use crate::task::{Context, Poll}; + +/// A stream that was created from iterator. +/// +/// This stream is created by the [`from_iter`] function. +/// See it documentation for more. +/// +/// [`from_iter`]: fn.from_iter.html +#[unstable(feature = "stream_from_iter", issue = "81798")] +#[derive(Clone, Debug)] +pub struct FromIter<I> { + iter: I, +} + +#[unstable(feature = "stream_from_iter", issue = "81798")] +impl<I> Unpin for FromIter<I> {} + +/// Converts an iterator into a stream. +#[unstable(feature = "stream_from_iter", issue = "81798")] +pub fn from_iter<I: IntoIterator>(iter: I) -> FromIter<I::IntoIter> { + FromIter { iter: iter.into_iter() } +} + +#[unstable(feature = "stream_from_iter", issue = "81798")] +impl<I: Iterator> Stream for FromIter<I> { + type Item = I::Item; + + fn poll_next(mut self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Option<Self::Item>> { + Poll::Ready(self.iter.next()) + } + + fn size_hint(&self) -> (usize, Option<usize>) { + self.iter.size_hint() + } +} diff --git a/library/core/src/stream/mod.rs b/library/core/src/stream/mod.rs index 0df18af65eb..58dc8e1e5e6 100644 --- a/library/core/src/stream/mod.rs +++ b/library/core/src/stream/mod.rs @@ -122,6 +122,8 @@ //! warning: unused result that must be used: streams do nothing unless polled //! ``` +mod from_iter; mod stream; +pub use from_iter::{from_iter, FromIter}; pub use stream::Stream; diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs index f1a115563fd..d9de37e9c51 100644 --- a/library/core/src/sync/atomic.rs +++ b/library/core/src/sync/atomic.rs @@ -41,7 +41,7 @@ //! instructions to implement `AtomicI8`. Note that this emulation should not //! have an impact on correctness of code, it's just something to be aware of. //! -//! The atomic types in this module may not be available on all platforms. The +//! The atomic types in this module might not be available on all platforms. The //! atomic types here are all widely available, however, and can generally be //! relied upon existing. Some notable exceptions are: //! @@ -113,6 +113,7 @@ #![stable(feature = "rust1", since = "1.0.0")] #![cfg_attr(not(target_has_atomic_load_store = "8"), allow(dead_code))] #![cfg_attr(not(target_has_atomic_load_store = "8"), allow(unused_imports))] +#![rustc_diagnostic_item = "atomic_mod"] use self::Ordering::*; @@ -137,7 +138,8 @@ pub struct AtomicBool { #[cfg(target_has_atomic_load_store = "8")] #[stable(feature = "rust1", since = "1.0.0")] -impl Default for AtomicBool { +#[rustc_const_unstable(feature = "const_default_impls", issue = "87864")] +impl const Default for AtomicBool { /// Creates an `AtomicBool` initialized to `false`. #[inline] fn default() -> Self { @@ -167,7 +169,8 @@ pub struct AtomicPtr<T> { #[cfg(target_has_atomic_load_store = "ptr")] #[stable(feature = "rust1", since = "1.0.0")] -impl<T> Default for AtomicPtr<T> { +#[rustc_const_unstable(feature = "const_default_impls", issue = "87864")] +impl<T> const Default for AtomicPtr<T> { /// Creates a null `AtomicPtr<T>`. fn default() -> AtomicPtr<T> { AtomicPtr::new(crate::ptr::null_mut()) @@ -198,6 +201,7 @@ unsafe impl<T> Sync for AtomicPtr<T> {} #[stable(feature = "rust1", since = "1.0.0")] #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] #[non_exhaustive] +#[rustc_diagnostic_item = "Ordering"] pub enum Ordering { /// No ordering constraints, only atomic operations. /// @@ -1349,7 +1353,8 @@ macro_rules! atomic_int { pub const $atomic_init: $atomic_type = $atomic_type::new(0); #[$stable] - impl Default for $atomic_type { + #[rustc_const_unstable(feature = "const_default_impls", issue = "87864")] + impl const Default for $atomic_type { #[inline] fn default() -> Self { Self::new(Default::default()) @@ -2648,7 +2653,11 @@ unsafe fn atomic_umin<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T { /// /// pub fn lock(&self) { /// // Wait until the old value is `false`. -/// while self.flag.compare_and_swap(false, true, Ordering::Relaxed) != false {} +/// while self +/// .flag +/// .compare_exchange_weak(false, true, Ordering::Relaxed, Ordering::Relaxed) +/// .is_err() +/// {} /// // This fence synchronizes-with store in `unlock`. /// fence(Ordering::Acquire); /// } @@ -2660,6 +2669,7 @@ unsafe fn atomic_umin<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] +#[rustc_diagnostic_item = "fence"] pub fn fence(order: Ordering) { // SAFETY: using an atomic fence is safe. unsafe { @@ -2710,7 +2720,7 @@ pub fn fence(order: Ordering) { /// Without `compiler_fence`, the `assert_eq!` in following code /// is *not* guaranteed to succeed, despite everything happening in a single thread. /// To see why, remember that the compiler is free to swap the stores to -/// `IMPORTANT_VARIABLE` and `IS_READ` since they are both +/// `IMPORTANT_VARIABLE` and `IS_READY` since they are both /// `Ordering::Relaxed`. If it does, and the signal handler is invoked right /// after `IS_READY` is updated, then the signal handler will see /// `IS_READY=1`, but `IMPORTANT_VARIABLE=0`. @@ -2741,6 +2751,7 @@ pub fn fence(order: Ordering) { /// [memory barriers]: https://www.kernel.org/doc/Documentation/memory-barriers.txt #[inline] #[stable(feature = "compiler_fences", since = "1.21.0")] +#[rustc_diagnostic_item = "compiler_fence"] pub fn compiler_fence(order: Ordering) { // SAFETY: using an atomic fence is safe. unsafe { diff --git a/library/core/src/task/mod.rs b/library/core/src/task/mod.rs index 3d6f4f5971a..5f077f77bbc 100644 --- a/library/core/src/task/mod.rs +++ b/library/core/src/task/mod.rs @@ -11,5 +11,5 @@ mod wake; pub use self::wake::{Context, RawWaker, RawWakerVTable, Waker}; mod ready; -#[unstable(feature = "ready_macro", issue = "70922")] +#[stable(feature = "ready_macro", since = "1.56.0")] pub use ready::ready; diff --git a/library/core/src/task/poll.rs b/library/core/src/task/poll.rs index 9cf89623d88..fc0a4e74797 100644 --- a/library/core/src/task/poll.rs +++ b/library/core/src/task/poll.rs @@ -26,7 +26,21 @@ pub enum Poll<T> { } impl<T> Poll<T> { - /// Changes the ready value of this `Poll` with the closure provided. + /// Maps a `Poll<T>` to `Poll<U>` by applying a function to a contained value. + /// + /// # Examples + /// + /// Converts a `Poll<`[`String`]`>` into an `Poll<`[`usize`]`>`, consuming the original: + /// + /// [`String`]: ../../std/string/struct.String.html + /// ``` + /// # use core::task::Poll; + /// let poll_some_string = Poll::Ready(String::from("Hello, World!")); + /// // `Poll::map` takes self *by value*, consuming `poll_some_string` + /// let poll_some_len = poll_some_string.map(|s| s.len()); + /// + /// assert_eq!(poll_some_len, Poll::Ready(13)); + /// ``` #[stable(feature = "futures_api", since = "1.36.0")] pub fn map<U, F>(self, f: F) -> Poll<U> where @@ -38,7 +52,18 @@ impl<T> Poll<T> { } } - /// Returns `true` if this is `Poll::Ready` + /// Returns `true` if the poll is a [`Poll::Ready`] value. + /// + /// # Examples + /// + /// ``` + /// # use core::task::Poll; + /// let x: Poll<u32> = Poll::Ready(2); + /// assert_eq!(x.is_ready(), true); + /// + /// let x: Poll<u32> = Poll::Pending; + /// assert_eq!(x.is_ready(), false); + /// ``` #[inline] #[rustc_const_stable(feature = "const_poll", since = "1.49.0")] #[stable(feature = "futures_api", since = "1.36.0")] @@ -46,7 +71,20 @@ impl<T> Poll<T> { matches!(*self, Poll::Ready(_)) } - /// Returns `true` if this is `Poll::Pending` + /// Returns `true` if the poll is a [`Pending`] value. + /// + /// [`Pending`]: Poll::Pending + /// + /// # Examples + /// + /// ``` + /// # use core::task::Poll; + /// let x: Poll<u32> = Poll::Ready(2); + /// assert_eq!(x.is_pending(), false); + /// + /// let x: Poll<u32> = Poll::Pending; + /// assert_eq!(x.is_pending(), true); + /// ``` #[inline] #[rustc_const_stable(feature = "const_poll", since = "1.49.0")] #[stable(feature = "futures_api", since = "1.36.0")] @@ -56,7 +94,20 @@ impl<T> Poll<T> { } impl<T, E> Poll<Result<T, E>> { - /// Changes the success value of this `Poll` with the closure provided. + /// Maps a `Poll<Result<T, E>>` to `Poll<Result<U, E>>` by applying a + /// function to a contained `Poll::Ready(Ok)` value, leaving all other + /// variants untouched. + /// + /// This function can be used to compose the results of two functions. + /// + /// # Examples + /// + /// ``` + /// # use core::task::Poll; + /// let res: Poll<Result<u8, _>> = Poll::Ready("12".parse()); + /// let squared = res.map_ok(|n| n * n); + /// assert_eq!(squared, Poll::Ready(Ok(144))); + /// ``` #[stable(feature = "futures_api", since = "1.36.0")] pub fn map_ok<U, F>(self, f: F) -> Poll<Result<U, E>> where @@ -69,7 +120,21 @@ impl<T, E> Poll<Result<T, E>> { } } - /// Changes the error value of this `Poll` with the closure provided. + /// Maps a `Poll::Ready<Result<T, E>>` to `Poll::Ready<Result<T, F>>` by + /// applying a function to a contained `Poll::Ready(Err)` value, leaving all other + /// variants untouched. + /// + /// This function can be used to pass through a successful result while handling + /// an error. + /// + /// # Examples + /// + /// ``` + /// # use core::task::Poll; + /// let res: Poll<Result<u8, _>> = Poll::Ready("oops".parse()); + /// let res = res.map_err(|_| 0_u8); + /// assert_eq!(res, Poll::Ready(Err(0))); + /// ``` #[stable(feature = "futures_api", since = "1.36.0")] pub fn map_err<U, F>(self, f: F) -> Poll<Result<T, U>> where @@ -84,7 +149,20 @@ impl<T, E> Poll<Result<T, E>> { } impl<T, E> Poll<Option<Result<T, E>>> { - /// Changes the success value of this `Poll` with the closure provided. + /// Maps a `Poll<Option<Result<T, E>>>` to `Poll<Option<Result<U, E>>>` by + /// applying a function to a contained `Poll::Ready(Some(Ok))` value, + /// leaving all other variants untouched. + /// + /// This function can be used to compose the results of two functions. + /// + /// # Examples + /// + /// ``` + /// # use core::task::Poll; + /// let res: Poll<Option<Result<u8, _>>> = Poll::Ready(Some("12".parse())); + /// let squared = res.map_ok(|n| n * n); + /// assert_eq!(squared, Poll::Ready(Some(Ok(144)))); + /// ``` #[stable(feature = "poll_map", since = "1.51.0")] pub fn map_ok<U, F>(self, f: F) -> Poll<Option<Result<U, E>>> where @@ -98,7 +176,22 @@ impl<T, E> Poll<Option<Result<T, E>>> { } } - /// Changes the error value of this `Poll` with the closure provided. + /// Maps a `Poll::Ready<Option<Result<T, E>>>` to + /// `Poll::Ready<Option<Result<T, F>>>` by applying a function to a + /// contained `Poll::Ready(Some(Err))` value, leaving all other variants + /// untouched. + /// + /// This function can be used to pass through a successful result while handling + /// an error. + /// + /// # Examples + /// + /// ``` + /// # use core::task::Poll; + /// let res: Poll<Option<Result<u8, _>>> = Poll::Ready(Some("oops".parse())); + /// let res = res.map_err(|_| 0_u8); + /// assert_eq!(res, Poll::Ready(Some(Err(0)))); + /// ``` #[stable(feature = "poll_map", since = "1.51.0")] pub fn map_err<U, F>(self, f: F) -> Poll<Option<Result<T, U>>> where @@ -128,32 +221,6 @@ impl<T> From<T> for Poll<T> { } } -#[stable(feature = "futures_api", since = "1.36.0")] -#[cfg(bootstrap)] -impl<T, E> ops::TryV1 for Poll<Result<T, E>> { - type Output = Poll<T>; - type Error = E; - - #[inline] - fn into_result(self) -> Result<Self::Output, Self::Error> { - match self { - Poll::Ready(Ok(x)) => Ok(Poll::Ready(x)), - Poll::Ready(Err(e)) => Err(e), - Poll::Pending => Ok(Poll::Pending), - } - } - - #[inline] - fn from_error(e: Self::Error) -> Self { - Poll::Ready(Err(e)) - } - - #[inline] - fn from_ok(x: Self::Output) -> Self { - x.map(Ok) - } -} - #[unstable(feature = "try_trait_v2", issue = "84277")] impl<T, E> ops::TryV2 for Poll<Result<T, E>> { type Output = Poll<T>; @@ -184,33 +251,6 @@ impl<T, E, F: From<E>> ops::FromResidual<Result<convert::Infallible, E>> for Pol } } -#[stable(feature = "futures_api", since = "1.36.0")] -#[cfg(bootstrap)] -impl<T, E> ops::TryV1 for Poll<Option<Result<T, E>>> { - type Output = Poll<Option<T>>; - type Error = E; - - #[inline] - fn into_result(self) -> Result<Self::Output, Self::Error> { - match self { - Poll::Ready(Some(Ok(x))) => Ok(Poll::Ready(Some(x))), - Poll::Ready(Some(Err(e))) => Err(e), - Poll::Ready(None) => Ok(Poll::Ready(None)), - Poll::Pending => Ok(Poll::Pending), - } - } - - #[inline] - fn from_error(e: Self::Error) -> Self { - Poll::Ready(Some(Err(e))) - } - - #[inline] - fn from_ok(x: Self::Output) -> Self { - x.map(|x| x.map(Ok)) - } -} - #[unstable(feature = "try_trait_v2", issue = "84277")] impl<T, E> ops::TryV2 for Poll<Option<Result<T, E>>> { type Output = Poll<Option<T>>; diff --git a/library/core/src/task/ready.rs b/library/core/src/task/ready.rs index cbf69900015..2834ca5fe22 100644 --- a/library/core/src/task/ready.rs +++ b/library/core/src/task/ready.rs @@ -8,8 +8,6 @@ /// # Examples /// /// ``` -/// #![feature(ready_macro)] -/// /// use std::task::{ready, Context, Poll}; /// use std::future::{self, Future}; /// use std::pin::Pin; @@ -29,8 +27,6 @@ /// The `ready!` call expands to: /// /// ``` -/// # #![feature(ready_macro)] -/// # /// # use std::task::{Context, Poll}; /// # use std::future::{self, Future}; /// # use std::pin::Pin; @@ -49,7 +45,7 @@ /// # Poll::Ready(()) /// # } /// ``` -#[unstable(feature = "ready_macro", issue = "70922")] +#[stable(feature = "ready_macro", since = "1.56.0")] #[rustc_macro_transparency = "semitransparent"] pub macro ready($e:expr) { match $e { diff --git a/library/core/src/time.rs b/library/core/src/time.rs index 489b7224403..2d8a1cb1ab0 100644 --- a/library/core/src/time.rs +++ b/library/core/src/time.rs @@ -61,6 +61,7 @@ const MICROS_PER_SEC: u64 = 1_000_000; /// crate to do so. #[stable(feature = "duration", since = "1.3.0")] #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)] +#[cfg_attr(not(test), rustc_diagnostic_item = "Duration")] pub struct Duration { secs: u64, nanos: u32, // Always 0 <= nanos < NANOS_PER_SEC @@ -687,21 +688,47 @@ impl Duration { #[inline] #[rustc_const_unstable(feature = "duration_consts_2", issue = "72440")] pub const fn from_secs_f64(secs: f64) -> Duration { + match Duration::try_from_secs_f64(secs) { + Ok(v) => v, + Err(e) => crate::panicking::panic(e.description()), + } + } + + /// The checked version of [`from_secs_f64`]. + /// + /// [`from_secs_f64`]: Duration::from_secs_f64 + /// + /// This constructor will return an `Err` if `secs` is not finite, negative or overflows `Duration`. + /// + /// # Examples + /// ``` + /// #![feature(duration_checked_float)] + /// + /// use std::time::Duration; + /// + /// let dur = Duration::try_from_secs_f64(2.7); + /// assert_eq!(dur, Ok(Duration::new(2, 700_000_000))); + /// + /// let negative = Duration::try_from_secs_f64(-5.0); + /// assert!(negative.is_err()); + /// ``` + #[unstable(feature = "duration_checked_float", issue = "83400")] + #[inline] + pub const fn try_from_secs_f64(secs: f64) -> Result<Duration, FromSecsError> { const MAX_NANOS_F64: f64 = ((u64::MAX as u128 + 1) * (NANOS_PER_SEC as u128)) as f64; let nanos = secs * (NANOS_PER_SEC as f64); if !nanos.is_finite() { - panic!("got non-finite value when converting float to duration"); - } - if nanos >= MAX_NANOS_F64 { - panic!("overflow when converting float to duration"); - } - if nanos < 0.0 { - panic!("underflow when converting float to duration"); - } - let nanos = nanos as u128; - Duration { - secs: (nanos / (NANOS_PER_SEC as u128)) as u64, - nanos: (nanos % (NANOS_PER_SEC as u128)) as u32, + Err(FromSecsError { kind: FromSecsErrorKind::NonFinite }) + } else if nanos >= MAX_NANOS_F64 { + Err(FromSecsError { kind: FromSecsErrorKind::Overflow }) + } else if nanos < 0.0 { + Err(FromSecsError { kind: FromSecsErrorKind::Underflow }) + } else { + let nanos = nanos as u128; + Ok(Duration { + secs: (nanos / (NANOS_PER_SEC as u128)) as u64, + nanos: (nanos % (NANOS_PER_SEC as u128)) as u32, + }) } } @@ -722,21 +749,47 @@ impl Duration { #[inline] #[rustc_const_unstable(feature = "duration_consts_2", issue = "72440")] pub const fn from_secs_f32(secs: f32) -> Duration { + match Duration::try_from_secs_f32(secs) { + Ok(v) => v, + Err(e) => crate::panicking::panic(e.description()), + } + } + + /// The checked version of [`from_secs_f32`]. + /// + /// [`from_secs_f32`]: Duration::from_secs_f32 + /// + /// This constructor will return an `Err` if `secs` is not finite, negative or overflows `Duration`. + /// + /// # Examples + /// ``` + /// #![feature(duration_checked_float)] + /// + /// use std::time::Duration; + /// + /// let dur = Duration::try_from_secs_f32(2.7); + /// assert_eq!(dur, Ok(Duration::new(2, 700_000_000))); + /// + /// let negative = Duration::try_from_secs_f32(-5.0); + /// assert!(negative.is_err()); + /// ``` + #[unstable(feature = "duration_checked_float", issue = "83400")] + #[inline] + pub const fn try_from_secs_f32(secs: f32) -> Result<Duration, FromSecsError> { const MAX_NANOS_F32: f32 = ((u64::MAX as u128 + 1) * (NANOS_PER_SEC as u128)) as f32; let nanos = secs * (NANOS_PER_SEC as f32); if !nanos.is_finite() { - panic!("got non-finite value when converting float to duration"); - } - if nanos >= MAX_NANOS_F32 { - panic!("overflow when converting float to duration"); - } - if nanos < 0.0 { - panic!("underflow when converting float to duration"); - } - let nanos = nanos as u128; - Duration { - secs: (nanos / (NANOS_PER_SEC as u128)) as u64, - nanos: (nanos % (NANOS_PER_SEC as u128)) as u32, + Err(FromSecsError { kind: FromSecsErrorKind::NonFinite }) + } else if nanos >= MAX_NANOS_F32 { + Err(FromSecsError { kind: FromSecsErrorKind::Overflow }) + } else if nanos < 0.0 { + Err(FromSecsError { kind: FromSecsErrorKind::Underflow }) + } else { + let nanos = nanos as u128; + Ok(Duration { + secs: (nanos / (NANOS_PER_SEC as u128)) as u64, + nanos: (nanos % (NANOS_PER_SEC as u128)) as u32, + }) } } @@ -1099,3 +1152,55 @@ impl fmt::Debug for Duration { } } } + +/// An error which can be returned when converting a floating-point value of seconds +/// into a [`Duration`]. +/// +/// This error is used as the error type for [`Duration::try_from_secs_f32`] and +/// [`Duration::try_from_secs_f64`]. +/// +/// # Example +/// +/// ``` +/// #![feature(duration_checked_float)] +/// +/// use std::time::Duration; +/// +/// if let Err(e) = Duration::try_from_secs_f32(-1.0) { +/// println!("Failed conversion to Duration: {}", e); +/// } +/// ``` +#[derive(Debug, Clone, PartialEq, Eq)] +#[unstable(feature = "duration_checked_float", issue = "83400")] +pub struct FromSecsError { + kind: FromSecsErrorKind, +} + +impl FromSecsError { + const fn description(&self) -> &'static str { + match self.kind { + FromSecsErrorKind::NonFinite => { + "got non-finite value when converting float to duration" + } + FromSecsErrorKind::Overflow => "overflow when converting float to duration", + FromSecsErrorKind::Underflow => "underflow when converting float to duration", + } + } +} + +#[unstable(feature = "duration_checked_float", issue = "83400")] +impl fmt::Display for FromSecsError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Display::fmt(self.description(), f) + } +} + +#[derive(Debug, Clone, PartialEq, Eq)] +enum FromSecsErrorKind { + // Value is not a finite value (either infinity or NaN). + NonFinite, + // Value is too large to store in a `Duration`. + Overflow, + // Value is less than `0.0`. + Underflow, +} diff --git a/library/core/src/unicode/mod.rs b/library/core/src/unicode/mod.rs index 37ca0a0779b..72fa059b787 100644 --- a/library/core/src/unicode/mod.rs +++ b/library/core/src/unicode/mod.rs @@ -4,7 +4,7 @@ pub(crate) mod printable; mod unicode_data; -/// The version of [Unicode](http://www.unicode.org/) that the Unicode parts of +/// The version of [Unicode](https://www.unicode.org/) that the Unicode parts of /// `char` and `str` methods are based on. /// /// New versions of Unicode are released regularly and subsequently all methods diff --git a/library/core/src/unicode/printable.py b/library/core/src/unicode/printable.py index 91db6381c9b..c42850d2324 100755 --- a/library/core/src/unicode/printable.py +++ b/library/core/src/unicode/printable.py @@ -130,7 +130,7 @@ def print_normal(normal, normalname): print("];") def main(): - file = get_file("http://www.unicode.org/Public/UNIDATA/UnicodeData.txt") + file = get_file("https://www.unicode.org/Public/UNIDATA/UnicodeData.txt") codepoints = get_codepoints(file) diff --git a/library/core/tests/char.rs b/library/core/tests/char.rs index c16f54081ce..51eca1e05d3 100644 --- a/library/core/tests/char.rs +++ b/library/core/tests/char.rs @@ -67,10 +67,20 @@ fn test_to_digit() { assert_eq!('A'.to_digit(16), Some(10)); assert_eq!('b'.to_digit(16), Some(11)); assert_eq!('B'.to_digit(16), Some(11)); + assert_eq!('A'.to_digit(36), Some(10)); assert_eq!('z'.to_digit(36), Some(35)); assert_eq!('Z'.to_digit(36), Some(35)); - assert_eq!(' '.to_digit(10), None); + assert_eq!('['.to_digit(36), None); + assert_eq!('`'.to_digit(36), None); + assert_eq!('{'.to_digit(36), None); assert_eq!('$'.to_digit(36), None); + assert_eq!('@'.to_digit(16), None); + assert_eq!('G'.to_digit(16), None); + assert_eq!('g'.to_digit(16), None); + assert_eq!(' '.to_digit(10), None); + assert_eq!('/'.to_digit(10), None); + assert_eq!(':'.to_digit(10), None); + assert_eq!(':'.to_digit(11), None); } #[test] diff --git a/library/core/tests/hash/mod.rs b/library/core/tests/hash/mod.rs index 1566d357490..72ccdd4848a 100644 --- a/library/core/tests/hash/mod.rs +++ b/library/core/tests/hash/mod.rs @@ -1,7 +1,7 @@ mod sip; use std::default::Default; -use std::hash::{Hash, Hasher}; +use std::hash::{BuildHasher, Hash, Hasher}; use std::rc::Rc; struct MyHasher { @@ -139,3 +139,10 @@ fn test_indirect_hasher() { } assert_eq!(hasher.hash, 5); } + +#[test] +fn test_build_hasher_object_safe() { + use std::collections::hash_map::{DefaultHasher, RandomState}; + + let _: &dyn BuildHasher<Hasher = DefaultHasher> = &RandomState::new(); +} diff --git a/library/core/tests/iter/adapters/flatten.rs b/library/core/tests/iter/adapters/flatten.rs index 4bbae6947bf..aaac39c2979 100644 --- a/library/core/tests/iter/adapters/flatten.rs +++ b/library/core/tests/iter/adapters/flatten.rs @@ -1,4 +1,5 @@ use super::*; +use core::array; use core::iter::*; #[test] @@ -109,3 +110,42 @@ fn test_double_ended_flatten() { assert_eq!(it.next(), None); assert_eq!(it.next_back(), None); } + +#[test] +fn test_trusted_len_flatten() { + fn assert_trusted_len<T: TrustedLen>(_: &T) {} + let mut iter = array::IntoIter::new([[0; 3]; 4]).flatten(); + assert_trusted_len(&iter); + + assert_eq!(iter.size_hint(), (12, Some(12))); + iter.next(); + assert_eq!(iter.size_hint(), (11, Some(11))); + iter.next_back(); + assert_eq!(iter.size_hint(), (10, Some(10))); + + let iter = array::IntoIter::new([[(); usize::MAX]; 1]).flatten(); + assert_eq!(iter.size_hint(), (usize::MAX, Some(usize::MAX))); + + let iter = array::IntoIter::new([[(); usize::MAX]; 2]).flatten(); + assert_eq!(iter.size_hint(), (usize::MAX, None)); + + let mut a = [(); 10]; + let mut b = [(); 10]; + + let iter = array::IntoIter::new([&mut a, &mut b]).flatten(); + assert_trusted_len(&iter); + assert_eq!(iter.size_hint(), (20, Some(20))); + core::mem::drop(iter); + + let iter = array::IntoIter::new([&a, &b]).flatten(); + assert_trusted_len(&iter); + assert_eq!(iter.size_hint(), (20, Some(20))); + + let iter = [(), (), ()].iter().flat_map(|_| [(); 1000]); + assert_trusted_len(&iter); + assert_eq!(iter.size_hint(), (3000, Some(3000))); + + let iter = [(), ()].iter().flat_map(|_| &a); + assert_trusted_len(&iter); + assert_eq!(iter.size_hint(), (20, Some(20))); +} diff --git a/library/core/tests/iter/adapters/mod.rs b/library/core/tests/iter/adapters/mod.rs index 96a53be1eaa..567d9fe49ca 100644 --- a/library/core/tests/iter/adapters/mod.rs +++ b/library/core/tests/iter/adapters/mod.rs @@ -24,7 +24,7 @@ use core::cell::Cell; /// An iterator that panics whenever `next` or next_back` is called /// after `None` has already been returned. This does not violate -/// `Iterator`'s contract. Used to test that iterator adaptors don't +/// `Iterator`'s contract. Used to test that iterator adapters don't /// poll their inner iterators after exhausting them. pub struct NonFused<I> { iter: I, diff --git a/library/core/tests/iter/adapters/zip.rs b/library/core/tests/iter/adapters/zip.rs index 797bfd957f9..585cfbb90e4 100644 --- a/library/core/tests/iter/adapters/zip.rs +++ b/library/core/tests/iter/adapters/zip.rs @@ -233,6 +233,33 @@ fn test_zip_trusted_random_access_composition() { } #[test] +#[cfg(panic = "unwind")] +fn test_zip_trusted_random_access_next_back_drop() { + use std::panic::catch_unwind; + use std::panic::AssertUnwindSafe; + + let mut counter = 0; + + let it = [42].iter().map(|e| { + let c = counter; + counter += 1; + if c == 0 { + panic!("bomb"); + } + + e + }); + let it2 = [(); 0].iter(); + let mut zip = it.zip(it2); + catch_unwind(AssertUnwindSafe(|| { + zip.next_back(); + })) + .unwrap_err(); + assert!(zip.next().is_none()); + assert_eq!(counter, 1); +} + +#[test] fn test_double_ended_zip() { let xs = [1, 2, 3, 4, 5, 6]; let ys = [1, 2, 3, 7]; diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index 16051b3bc36..13f483f19b7 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -1,10 +1,8 @@ #![feature(alloc_layout_extra)] #![feature(array_chunks)] #![feature(array_methods)] -#![feature(array_map)] #![feature(array_windows)] #![feature(bool_to_option)] -#![feature(bound_cloned)] #![feature(box_syntax)] #![feature(cell_update)] #![feature(cfg_panic)] @@ -15,7 +13,8 @@ #![feature(const_ptr_read)] #![feature(const_ptr_write)] #![feature(const_ptr_offset)] -#![feature(control_flow_enum)] +#![feature(const_trait_impl)] +#![feature(const_num_from_num)] #![feature(core_intrinsics)] #![feature(core_private_bignum)] #![feature(core_private_diy_float)] @@ -31,7 +30,6 @@ #![feature(try_find)] #![feature(is_sorted)] #![feature(pattern)] -#![feature(raw)] #![feature(sort_internals)] #![feature(slice_partition_at_index)] #![feature(maybe_uninit_uninit_array)] @@ -39,6 +37,7 @@ #![feature(maybe_uninit_extra)] #![feature(maybe_uninit_write_slice)] #![feature(min_specialization)] +#![feature(numfmt)] #![feature(step_trait)] #![feature(str_internals)] #![feature(test)] @@ -46,7 +45,7 @@ #![feature(try_trait_v2)] #![feature(slice_internals)] #![feature(slice_partition_dedup)] -#![feature(int_error_matching)] +#![feature(int_log)] #![feature(iter_advance_by)] #![feature(iter_partition_in_place)] #![feature(iter_intersperse)] @@ -69,6 +68,7 @@ #![feature(slice_group_by)] #![feature(trusted_random_access)] #![feature(unsize)] +#![feature(unzip_option)] #![deny(unsafe_op_in_unsafe_fn)] extern crate test; diff --git a/library/core/tests/macros.rs b/library/core/tests/macros.rs index 482f3c1c998..ff3632e3550 100644 --- a/library/core/tests/macros.rs +++ b/library/core/tests/macros.rs @@ -12,3 +12,9 @@ fn assert_escape() { fn assert_ne_trailing_comma() { assert_ne!(1, 2,); } + +#[rustfmt::skip] +#[test] +fn matches_leading_pipe() { + matches!(1, | 1 | 2 | 3); +} diff --git a/library/core/tests/manually_drop.rs b/library/core/tests/manually_drop.rs index 77a338daf7d..9eac279733a 100644 --- a/library/core/tests/manually_drop.rs +++ b/library/core/tests/manually_drop.rs @@ -2,6 +2,7 @@ use core::mem::ManuallyDrop; #[test] fn smoke() { + #[derive(Clone)] struct TypeWithDrop; impl Drop for TypeWithDrop { fn drop(&mut self) { @@ -16,4 +17,11 @@ fn smoke() { let x: Box<ManuallyDrop<[TypeWithDrop]>> = Box::new(ManuallyDrop::new([TypeWithDrop, TypeWithDrop])); drop(x); + + // test clone and clone_from implementations + let mut x = ManuallyDrop::new(TypeWithDrop); + let y = x.clone(); + x.clone_from(&y); + drop(x); + drop(y); } diff --git a/library/core/tests/mem.rs b/library/core/tests/mem.rs index dfdbc9305d2..c780bb32ca9 100644 --- a/library/core/tests/mem.rs +++ b/library/core/tests/mem.rs @@ -97,28 +97,6 @@ fn test_transmute_copy() { assert_eq!(1, unsafe { transmute_copy(&1) }); } -// Remove this test when `std::raw` is removed. -// The replacement pointer metadata APIs are tested in library/core/tests/ptr.rs -#[allow(deprecated)] -#[test] -fn test_transmute() { - trait Foo { - fn dummy(&self) {} - } - impl Foo for isize {} - - let a = box 100isize as Box<dyn Foo>; - unsafe { - let x: ::core::raw::TraitObject = transmute(a); - assert!(*(x.data as *const isize) == 100); - let _x: Box<dyn Foo> = transmute(x); - } - - unsafe { - assert_eq!(transmute::<_, Vec<u8>>("L".to_string()), [76]); - } -} - #[test] #[allow(dead_code)] fn test_discriminant_send_sync() { diff --git a/library/core/tests/num/const_from.rs b/library/core/tests/num/const_from.rs new file mode 100644 index 00000000000..aca18ef39de --- /dev/null +++ b/library/core/tests/num/const_from.rs @@ -0,0 +1,25 @@ +#[test] +fn from() { + use core::convert::TryFrom; + use core::num::TryFromIntError; + + // From + const FROM: i64 = i64::from(1i32); + assert_eq!(FROM, 1i64); + + // From int to float + const FROM_F64: f64 = f64::from(42u8); + assert_eq!(FROM_F64, 42f64); + + // Upper bounded + const U8_FROM_U16: Result<u8, TryFromIntError> = u8::try_from(1u16); + assert_eq!(U8_FROM_U16, Ok(1u8)); + + // Both bounded + const I8_FROM_I16: Result<i8, TryFromIntError> = i8::try_from(1i16); + assert_eq!(I8_FROM_I16, Ok(1i8)); + + // Lower bounded + const I16_FROM_U16: Result<i16, TryFromIntError> = i16::try_from(1u16); + assert_eq!(I16_FROM_U16, Ok(1i16)); +} diff --git a/library/core/tests/num/dec2flt/float.rs b/library/core/tests/num/dec2flt/float.rs new file mode 100644 index 00000000000..7a9587a18d0 --- /dev/null +++ b/library/core/tests/num/dec2flt/float.rs @@ -0,0 +1,33 @@ +use core::num::dec2flt::float::RawFloat; + +#[test] +fn test_f32_integer_decode() { + assert_eq!(3.14159265359f32.integer_decode(), (13176795, -22, 1)); + assert_eq!((-8573.5918555f32).integer_decode(), (8779358, -10, -1)); + assert_eq!(2f32.powf(100.0).integer_decode(), (8388608, 77, 1)); + assert_eq!(0f32.integer_decode(), (0, -150, 1)); + assert_eq!((-0f32).integer_decode(), (0, -150, -1)); + assert_eq!(f32::INFINITY.integer_decode(), (8388608, 105, 1)); + assert_eq!(f32::NEG_INFINITY.integer_decode(), (8388608, 105, -1)); + + // Ignore the "sign" (quiet / signalling flag) of NAN. + // It can vary between runtime operations and LLVM folding. + let (nan_m, nan_e, _nan_s) = f32::NAN.integer_decode(); + assert_eq!((nan_m, nan_e), (12582912, 105)); +} + +#[test] +fn test_f64_integer_decode() { + assert_eq!(3.14159265359f64.integer_decode(), (7074237752028906, -51, 1)); + assert_eq!((-8573.5918555f64).integer_decode(), (4713381968463931, -39, -1)); + assert_eq!(2f64.powf(100.0).integer_decode(), (4503599627370496, 48, 1)); + assert_eq!(0f64.integer_decode(), (0, -1075, 1)); + assert_eq!((-0f64).integer_decode(), (0, -1075, -1)); + assert_eq!(f64::INFINITY.integer_decode(), (4503599627370496, 972, 1)); + assert_eq!(f64::NEG_INFINITY.integer_decode(), (4503599627370496, 972, -1)); + + // Ignore the "sign" (quiet / signalling flag) of NAN. + // It can vary between runtime operations and LLVM folding. + let (nan_m, nan_e, _nan_s) = f64::NAN.integer_decode(); + assert_eq!((nan_m, nan_e), (6755399441055744, 972)); +} diff --git a/library/core/tests/num/dec2flt/lemire.rs b/library/core/tests/num/dec2flt/lemire.rs new file mode 100644 index 00000000000..f71bbb7c7a3 --- /dev/null +++ b/library/core/tests/num/dec2flt/lemire.rs @@ -0,0 +1,53 @@ +use core::num::dec2flt::lemire::compute_float; + +fn compute_float32(q: i64, w: u64) -> (i32, u64) { + let fp = compute_float::<f32>(q, w); + (fp.e, fp.f) +} + +fn compute_float64(q: i64, w: u64) -> (i32, u64) { + let fp = compute_float::<f64>(q, w); + (fp.e, fp.f) +} + +#[test] +fn compute_float_f32_rounding() { + // These test near-halfway cases for single-precision floats. + assert_eq!(compute_float32(0, 16777216), (151, 0)); + assert_eq!(compute_float32(0, 16777217), (151, 0)); + assert_eq!(compute_float32(0, 16777218), (151, 1)); + assert_eq!(compute_float32(0, 16777219), (151, 2)); + assert_eq!(compute_float32(0, 16777220), (151, 2)); + + // These are examples of the above tests, with + // digits from the exponent shifted to the mantissa. + assert_eq!(compute_float32(-10, 167772160000000000), (151, 0)); + assert_eq!(compute_float32(-10, 167772170000000000), (151, 0)); + assert_eq!(compute_float32(-10, 167772180000000000), (151, 1)); + // Let's check the lines to see if anything is different in table... + assert_eq!(compute_float32(-10, 167772190000000000), (151, 2)); + assert_eq!(compute_float32(-10, 167772200000000000), (151, 2)); +} + +#[test] +fn compute_float_f64_rounding() { + // These test near-halfway cases for double-precision floats. + assert_eq!(compute_float64(0, 9007199254740992), (1076, 0)); + assert_eq!(compute_float64(0, 9007199254740993), (1076, 0)); + assert_eq!(compute_float64(0, 9007199254740994), (1076, 1)); + assert_eq!(compute_float64(0, 9007199254740995), (1076, 2)); + assert_eq!(compute_float64(0, 9007199254740996), (1076, 2)); + assert_eq!(compute_float64(0, 18014398509481984), (1077, 0)); + assert_eq!(compute_float64(0, 18014398509481986), (1077, 0)); + assert_eq!(compute_float64(0, 18014398509481988), (1077, 1)); + assert_eq!(compute_float64(0, 18014398509481990), (1077, 2)); + assert_eq!(compute_float64(0, 18014398509481992), (1077, 2)); + + // These are examples of the above tests, with + // digits from the exponent shifted to the mantissa. + assert_eq!(compute_float64(-3, 9007199254740992000), (1076, 0)); + assert_eq!(compute_float64(-3, 9007199254740993000), (1076, 0)); + assert_eq!(compute_float64(-3, 9007199254740994000), (1076, 1)); + assert_eq!(compute_float64(-3, 9007199254740995000), (1076, 2)); + assert_eq!(compute_float64(-3, 9007199254740996000), (1076, 2)); +} diff --git a/library/core/tests/num/dec2flt/mod.rs b/library/core/tests/num/dec2flt/mod.rs index 32f05d1def5..4990d4a083d 100644 --- a/library/core/tests/num/dec2flt/mod.rs +++ b/library/core/tests/num/dec2flt/mod.rs @@ -1,7 +1,8 @@ #![allow(overflowing_literals)] +mod float; +mod lemire; mod parse; -mod rawfp; // Take a float literal, turn it into a string in various ways (that are all trusted // to be correct) and see if those strings are parsed back to the value of the literal. @@ -28,12 +29,6 @@ fn ordinary() { test_literal!(0.1); test_literal!(12345.); test_literal!(0.9999999); - - if cfg!(miri) { - // Miri is too slow - return; - } - test_literal!(2.2250738585072014e-308); } @@ -54,7 +49,6 @@ fn large() { } #[test] -#[cfg_attr(miri, ignore)] // Miri is too slow fn subnormals() { test_literal!(5e-324); test_literal!(91e-324); @@ -66,7 +60,6 @@ fn subnormals() { } #[test] -#[cfg_attr(miri, ignore)] // Miri is too slow fn infinity() { test_literal!(1e400); test_literal!(1e309); @@ -78,12 +71,6 @@ fn infinity() { fn zero() { test_literal!(0.0); test_literal!(1e-325); - - if cfg!(miri) { - // Miri is too slow - return; - } - test_literal!(1e-326); test_literal!(1e-500); } diff --git a/library/core/tests/num/dec2flt/parse.rs b/library/core/tests/num/dec2flt/parse.rs index bb7e51d3002..473feacc91f 100644 --- a/library/core/tests/num/dec2flt/parse.rs +++ b/library/core/tests/num/dec2flt/parse.rs @@ -1,17 +1,23 @@ -use core::num::dec2flt::parse::ParseResult::{Invalid, Valid}; -use core::num::dec2flt::parse::{parse_decimal, Decimal}; +use core::num::dec2flt::number::Number; +use core::num::dec2flt::parse::parse_number; +use core::num::dec2flt::{dec2flt, pfe_invalid}; + +fn new_number(e: i64, m: u64) -> Number { + Number { exponent: e, mantissa: m, negative: false, many_digits: false } +} #[test] fn missing_pieces() { let permutations = &[".e", "1e", "e4", "e", ".12e", "321.e", "32.12e+", "12.32e-"]; for &s in permutations { - assert_eq!(parse_decimal(s), Invalid); + assert_eq!(dec2flt::<f64>(s), Err(pfe_invalid())); } } #[test] fn invalid_chars() { let invalid = "r,?<j"; + let error = Err(pfe_invalid()); let valid_strings = &["123", "666.", ".1", "5e1", "7e-3", "0.0e+1"]; for c in invalid.chars() { for s in valid_strings { @@ -19,23 +25,153 @@ fn invalid_chars() { let mut input = String::new(); input.push_str(s); input.insert(i, c); - assert!(parse_decimal(&input) == Invalid, "did not reject invalid {:?}", input); + assert!(dec2flt::<f64>(&input) == error, "did not reject invalid {:?}", input); } } } } +fn parse_positive(s: &[u8]) -> Option<Number> { + parse_number(s, false) +} + #[test] fn valid() { - assert_eq!(parse_decimal("123.456e789"), Valid(Decimal::new(b"123", b"456", 789))); - assert_eq!(parse_decimal("123.456e+789"), Valid(Decimal::new(b"123", b"456", 789))); - assert_eq!(parse_decimal("123.456e-789"), Valid(Decimal::new(b"123", b"456", -789))); - assert_eq!(parse_decimal(".050"), Valid(Decimal::new(b"", b"050", 0))); - assert_eq!(parse_decimal("999"), Valid(Decimal::new(b"999", b"", 0))); - assert_eq!(parse_decimal("1.e300"), Valid(Decimal::new(b"1", b"", 300))); - assert_eq!(parse_decimal(".1e300"), Valid(Decimal::new(b"", b"1", 300))); - assert_eq!(parse_decimal("101e-33"), Valid(Decimal::new(b"101", b"", -33))); + assert_eq!(parse_positive(b"123.456e789"), Some(new_number(786, 123456))); + assert_eq!(parse_positive(b"123.456e+789"), Some(new_number(786, 123456))); + assert_eq!(parse_positive(b"123.456e-789"), Some(new_number(-792, 123456))); + assert_eq!(parse_positive(b".050"), Some(new_number(-3, 50))); + assert_eq!(parse_positive(b"999"), Some(new_number(0, 999))); + assert_eq!(parse_positive(b"1.e300"), Some(new_number(300, 1))); + assert_eq!(parse_positive(b".1e300"), Some(new_number(299, 1))); + assert_eq!(parse_positive(b"101e-33"), Some(new_number(-33, 101))); let zeros = "0".repeat(25); let s = format!("1.5e{}", zeros); - assert_eq!(parse_decimal(&s), Valid(Decimal::new(b"1", b"5", 0))); + assert_eq!(parse_positive(s.as_bytes()), Some(new_number(-1, 15))); +} + +macro_rules! assert_float_result_bits_eq { + ($bits:literal, $ty:ty, $str:literal) => {{ + let p = dec2flt::<$ty>($str); + assert_eq!(p.map(|x| x.to_bits()), Ok($bits)); + }}; +} + +#[test] +fn issue31109() { + // Regression test for #31109. + // Ensure the test produces a valid float with the expected bit pattern. + assert_float_result_bits_eq!( + 0x3fd5555555555555, + f64, + "0.3333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333" + ); +} + +#[test] +fn issue31407() { + // Regression test for #31407. + // Ensure the test produces a valid float with the expected bit pattern. + assert_float_result_bits_eq!( + 0x1752a64e34ba0d3, + f64, + "1234567890123456789012345678901234567890e-340" + ); + assert_float_result_bits_eq!( + 0xfffffffffffff, + f64, + "2.225073858507201136057409796709131975934819546351645648023426109724822222021076945516529523908135087914149158913039621106870086438694594645527657207407820621743379988141063267329253552286881372149012981122451451889849057222307285255133155755015914397476397983411801999323962548289017107081850690630666655994938275772572015763062690663332647565300009245888316433037779791869612049497390377829704905051080609940730262937128958950003583799967207254304360284078895771796150945516748243471030702609144621572289880258182545180325707018860872113128079512233426288368622321503775666622503982534335974568884423900265498198385487948292206894721689831099698365846814022854243330660339850886445804001034933970427567186443383770486037861622771738545623065874679014086723327636718749999999999999999999999999999999999999e-308" + ); + assert_float_result_bits_eq!( + 0x10000000000000, + f64, + "2.22507385850720113605740979670913197593481954635164564802342610972482222202107694551652952390813508791414915891303962110687008643869459464552765720740782062174337998814106326732925355228688137214901298112245145188984905722230728525513315575501591439747639798341180199932396254828901710708185069063066665599493827577257201576306269066333264756530000924588831643303777979186961204949739037782970490505108060994073026293712895895000358379996720725430436028407889577179615094551674824347103070260914462157228988025818254518032570701886087211312807951223342628836862232150377566662250398253433597456888442390026549819838548794829220689472168983109969836584681402285424333066033985088644580400103493397042756718644338377048603786162277173854562306587467901408672332763671875e-308" + ); + assert_float_result_bits_eq!( + 0x10000000000000, + f64, + "0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000222507385850720138309023271733240406421921598046233183055332741688720443481391819585428315901251102056406733973103581100515243416155346010885601238537771882113077799353200233047961014744258363607192156504694250373420837525080665061665815894872049117996859163964850063590877011830487479978088775374994945158045160505091539985658247081864511353793580499211598108576605199243335211435239014879569960959128889160299264151106346631339366347758651302937176204732563178148566435087212282863764204484681140761391147706280168985324411002416144742161856716615054015428508471675290190316132277889672970737312333408698898317506783884692609277397797285865965494109136909540613646756870239867831529068098461721092462539672851562500000000000000001" + ); + assert_float_result_bits_eq!( + 0x7fefffffffffffff, + f64, + "179769313486231580793728971405303415079934132710037826936173778980444968292764750946649017977587207096330286416692887910946555547851940402630657488671505820681908902000708383676273854845817711531764475730270069855571366959622842914819860834936475292719074168444365510704342711559699508093042880177904174497791.9999999999999999999999999999999999999999999999999999999999999999999999" + ); + assert_float_result_bits_eq!(0x0, f64, "2.47032822920623272e-324"); + assert_float_result_bits_eq!( + 0x8000000, + f64, + "6.631236871469758276785396630275967243399099947355303144249971758736286630139265439618068200788048744105960420552601852889715006376325666595539603330361800519107591783233358492337208057849499360899425128640718856616503093444922854759159988160304439909868291973931426625698663157749836252274523485312442358651207051292453083278116143932569727918709786004497872322193856150225415211997283078496319412124640111777216148110752815101775295719811974338451936095907419622417538473679495148632480391435931767981122396703443803335529756003353209830071832230689201383015598792184172909927924176339315507402234836120730914783168400715462440053817592702766213559042115986763819482654128770595766806872783349146967171293949598850675682115696218943412532098591327667236328125E-316" + ); + assert_float_result_bits_eq!( + 0x10000, + f64, + "3.237883913302901289588352412501532174863037669423108059901297049552301970670676565786835742587799557860615776559838283435514391084153169252689190564396459577394618038928365305143463955100356696665629202017331344031730044369360205258345803431471660032699580731300954848363975548690010751530018881758184174569652173110473696022749934638425380623369774736560008997404060967498028389191878963968575439222206416981462690113342524002724385941651051293552601421155333430225237291523843322331326138431477823591142408800030775170625915670728657003151953664260769822494937951845801530895238439819708403389937873241463484205608000027270531106827387907791444918534771598750162812548862768493201518991668028251730299953143924168545708663913273994694463908672332763671875E-319" + ); + assert_float_result_bits_eq!( + 0x800000000100, + f64, + "6.953355807847677105972805215521891690222119817145950754416205607980030131549636688806115726399441880065386399864028691275539539414652831584795668560082999889551357784961446896042113198284213107935110217162654939802416034676213829409720583759540476786936413816541621287843248433202369209916612249676005573022703244799714622116542188837770376022371172079559125853382801396219552418839469770514904192657627060319372847562301074140442660237844114174497210955449896389180395827191602886654488182452409583981389442783377001505462015745017848754574668342161759496661766020028752888783387074850773192997102997936619876226688096314989645766000479009083731736585750335262099860150896718774401964796827166283225641992040747894382698751809812609536720628966577351093292236328125E-310" + ); + assert_float_result_bits_eq!( + 0x10800, + f64, + "3.339068557571188581835713701280943911923401916998521771655656997328440314559615318168849149074662609099998113009465566426808170378434065722991659642619467706034884424989741080790766778456332168200464651593995817371782125010668346652995912233993254584461125868481633343674905074271064409763090708017856584019776878812425312008812326260363035474811532236853359905334625575404216060622858633280744301892470300555678734689978476870369853549413277156622170245846166991655321535529623870646888786637528995592800436177901746286272273374471701452991433047257863864601424252024791567368195056077320885329384322332391564645264143400798619665040608077549162173963649264049738362290606875883456826586710961041737908872035803481241600376705491726170293986797332763671875E-319" + ); + assert_float_result_bits_eq!( + 0x0, + f64, + "2.4703282292062327208828439643411068618252990130716238221279284125033775363510437593264991818081799618989828234772285886546332835517796989819938739800539093906315035659515570226392290858392449105184435931802849936536152500319370457678249219365623669863658480757001585769269903706311928279558551332927834338409351978015531246597263579574622766465272827220056374006485499977096599470454020828166226237857393450736339007967761930577506740176324673600968951340535537458516661134223766678604162159680461914467291840300530057530849048765391711386591646239524912623653881879636239373280423891018672348497668235089863388587925628302755995657524455507255189313690836254779186948667994968324049705821028513185451396213837722826145437693412532098591327667236328124999e-324" + ); + assert_float_result_bits_eq!( + 0x0, + f64, + "2.4703282292062327208828439643411068618252990130716238221279284125033775363510437593264991818081799618989828234772285886546332835517796989819938739800539093906315035659515570226392290858392449105184435931802849936536152500319370457678249219365623669863658480757001585769269903706311928279558551332927834338409351978015531246597263579574622766465272827220056374006485499977096599470454020828166226237857393450736339007967761930577506740176324673600968951340535537458516661134223766678604162159680461914467291840300530057530849048765391711386591646239524912623653881879636239373280423891018672348497668235089863388587925628302755995657524455507255189313690836254779186948667994968324049705821028513185451396213837722826145437693412532098591327667236328125e-324" + ); + assert_float_result_bits_eq!( + 0x1, + f64, + "2.4703282292062327208828439643411068618252990130716238221279284125033775363510437593264991818081799618989828234772285886546332835517796989819938739800539093906315035659515570226392290858392449105184435931802849936536152500319370457678249219365623669863658480757001585769269903706311928279558551332927834338409351978015531246597263579574622766465272827220056374006485499977096599470454020828166226237857393450736339007967761930577506740176324673600968951340535537458516661134223766678604162159680461914467291840300530057530849048765391711386591646239524912623653881879636239373280423891018672348497668235089863388587925628302755995657524455507255189313690836254779186948667994968324049705821028513185451396213837722826145437693412532098591327667236328125001e-324" + ); + assert_float_result_bits_eq!( + 0x1, + f64, + "7.4109846876186981626485318930233205854758970392148714663837852375101326090531312779794975454245398856969484704316857659638998506553390969459816219401617281718945106978546710679176872575177347315553307795408549809608457500958111373034747658096871009590975442271004757307809711118935784838675653998783503015228055934046593739791790738723868299395818481660169122019456499931289798411362062484498678713572180352209017023903285791732520220528974020802906854021606612375549983402671300035812486479041385743401875520901590172592547146296175134159774938718574737870961645638908718119841271673056017045493004705269590165763776884908267986972573366521765567941072508764337560846003984904972149117463085539556354188641513168478436313080237596295773983001708984374999e-324" + ); + assert_float_result_bits_eq!( + 0x2, + f64, + "7.4109846876186981626485318930233205854758970392148714663837852375101326090531312779794975454245398856969484704316857659638998506553390969459816219401617281718945106978546710679176872575177347315553307795408549809608457500958111373034747658096871009590975442271004757307809711118935784838675653998783503015228055934046593739791790738723868299395818481660169122019456499931289798411362062484498678713572180352209017023903285791732520220528974020802906854021606612375549983402671300035812486479041385743401875520901590172592547146296175134159774938718574737870961645638908718119841271673056017045493004705269590165763776884908267986972573366521765567941072508764337560846003984904972149117463085539556354188641513168478436313080237596295773983001708984375e-324" + ); + assert_float_result_bits_eq!( + 0x2, + f64, + "7.4109846876186981626485318930233205854758970392148714663837852375101326090531312779794975454245398856969484704316857659638998506553390969459816219401617281718945106978546710679176872575177347315553307795408549809608457500958111373034747658096871009590975442271004757307809711118935784838675653998783503015228055934046593739791790738723868299395818481660169122019456499931289798411362062484498678713572180352209017023903285791732520220528974020802906854021606612375549983402671300035812486479041385743401875520901590172592547146296175134159774938718574737870961645638908718119841271673056017045493004705269590165763776884908267986972573366521765567941072508764337560846003984904972149117463085539556354188641513168478436313080237596295773983001708984375001e-324" + ); + assert_float_result_bits_eq!( + 0x6c9a143590c14, + f64, + "94393431193180696942841837085033647913224148539854e-358" + ); + assert_float_result_bits_eq!( + 0x7802665fd9600, + f64, + "104308485241983990666713401708072175773165034278685682646111762292409330928739751702404658197872319129036519947435319418387839758990478549477777586673075945844895981012024387992135617064532141489278815239849108105951619997829153633535314849999674266169258928940692239684771590065027025835804863585454872499320500023126142553932654370362024104462255244034053203998964360882487378334860197725139151265590832887433736189468858614521708567646743455601905935595381852723723645799866672558576993978025033590728687206296379801363024094048327273913079612469982585674824156000783167963081616214710691759864332339239688734656548790656486646106983450809073750535624894296242072010195710276073042036425579852459556183541199012652571123898996574563824424330960027873516082763671875e-1075" + ); +} + +#[test] +fn many_digits() { + // Check large numbers of digits to ensure we have cases where significant + // digits (above Decimal::MAX_DIGITS) occurs. + assert_float_result_bits_eq!( + 0x7ffffe, + f32, + "1.175494140627517859246175898662808184331245864732796240031385942718174675986064769972472277004271745681762695312500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e-38" + ); + assert_float_result_bits_eq!( + 0x7ffffe, + f32, + "1.175494140627517859246175898662808184331245864732796240031385942718174675986064769972472277004271745681762695312500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e-38" + ); } diff --git a/library/core/tests/num/dec2flt/rawfp.rs b/library/core/tests/num/dec2flt/rawfp.rs deleted file mode 100644 index 34a37209d99..00000000000 --- a/library/core/tests/num/dec2flt/rawfp.rs +++ /dev/null @@ -1,172 +0,0 @@ -use core::num::dec2flt::rawfp::RawFloat; -use core::num::dec2flt::rawfp::{fp_to_float, next_float, prev_float, round_normal}; -use core::num::diy_float::Fp; - -fn integer_decode(f: f64) -> (u64, i16, i8) { - RawFloat::integer_decode(f) -} - -#[test] -fn fp_to_float_half_to_even() { - fn is_normalized(sig: u64) -> bool { - // intentionally written without {min,max}_sig() as a sanity check - sig >> 52 == 1 && sig >> 53 == 0 - } - - fn conv(sig: u64) -> u64 { - // The significands are perfectly in range, so the exponent should not matter - let (m1, e1, _) = integer_decode(fp_to_float::<f64>(Fp { f: sig, e: 0 })); - assert_eq!(e1, 0 + 64 - 53); - let (m2, e2, _) = integer_decode(fp_to_float::<f64>(Fp { f: sig, e: 55 })); - assert_eq!(e2, 55 + 64 - 53); - assert_eq!(m2, m1); - let (m3, e3, _) = integer_decode(fp_to_float::<f64>(Fp { f: sig, e: -78 })); - assert_eq!(e3, -78 + 64 - 53); - assert_eq!(m3, m2); - m3 - } - - let odd = 0x1F_EDCB_A012_345F; - let even = odd - 1; - assert!(is_normalized(odd)); - assert!(is_normalized(even)); - assert_eq!(conv(odd << 11), odd); - assert_eq!(conv(even << 11), even); - assert_eq!(conv(odd << 11 | 1 << 10), odd + 1); - assert_eq!(conv(even << 11 | 1 << 10), even); - assert_eq!(conv(even << 11 | 1 << 10 | 1), even + 1); - assert_eq!(conv(odd << 11 | 1 << 9), odd); - assert_eq!(conv(even << 11 | 1 << 9), even); - assert_eq!(conv(odd << 11 | 0x7FF), odd + 1); - assert_eq!(conv(even << 11 | 0x7FF), even + 1); - assert_eq!(conv(odd << 11 | 0x3FF), odd); - assert_eq!(conv(even << 11 | 0x3FF), even); -} - -#[test] -fn integers_to_f64() { - assert_eq!(fp_to_float::<f64>(Fp { f: 1, e: 0 }), 1.0); - assert_eq!(fp_to_float::<f64>(Fp { f: 42, e: 7 }), (42 << 7) as f64); - assert_eq!(fp_to_float::<f64>(Fp { f: 1 << 20, e: 30 }), (1u64 << 50) as f64); - assert_eq!(fp_to_float::<f64>(Fp { f: 4, e: -3 }), 0.5); -} - -const SOME_FLOATS: [f64; 9] = [ - 0.1f64, - 33.568, - 42.1e-5, - 777.0e9, - 1.1111, - 0.347997, - 9843579834.35892, - 12456.0e-150, - 54389573.0e-150, -]; - -#[test] -fn human_f64_roundtrip() { - for &x in &SOME_FLOATS { - let (f, e, _) = integer_decode(x); - let fp = Fp { f: f, e: e }; - assert_eq!(fp_to_float::<f64>(fp), x); - } -} - -#[test] -fn rounding_overflow() { - let x = Fp { f: 0xFF_FF_FF_FF_FF_FF_FF_00u64, e: 42 }; - let rounded = round_normal::<f64>(x); - let adjusted_k = x.e + 64 - 53; - assert_eq!(rounded.sig, 1 << 52); - assert_eq!(rounded.k, adjusted_k + 1); -} - -#[test] -fn prev_float_monotonic() { - let mut x = 1.0; - for _ in 0..100 { - let x1 = prev_float(x); - assert!(x1 < x); - assert!(x - x1 < 1e-15); - x = x1; - } -} - -const MIN_SUBNORMAL: f64 = 5e-324; - -#[test] -fn next_float_zero() { - let tiny = next_float(0.0); - assert_eq!(tiny, MIN_SUBNORMAL); - assert!(tiny != 0.0); -} - -#[test] -fn next_float_subnormal() { - let second = next_float(MIN_SUBNORMAL); - // For subnormals, MIN_SUBNORMAL is the ULP - assert!(second != MIN_SUBNORMAL); - assert!(second > 0.0); - assert_eq!(second - MIN_SUBNORMAL, MIN_SUBNORMAL); -} - -#[test] -fn next_float_inf() { - assert_eq!(next_float(f64::MAX), f64::INFINITY); - assert_eq!(next_float(f64::INFINITY), f64::INFINITY); -} - -#[test] -fn next_prev_identity() { - for &x in &SOME_FLOATS { - assert_eq!(prev_float(next_float(x)), x); - assert_eq!(prev_float(prev_float(next_float(next_float(x)))), x); - assert_eq!(next_float(prev_float(x)), x); - assert_eq!(next_float(next_float(prev_float(prev_float(x)))), x); - } -} - -#[test] -fn next_float_monotonic() { - let mut x = 0.49999999999999; - assert!(x < 0.5); - for _ in 0..200 { - let x1 = next_float(x); - assert!(x1 > x); - assert!(x1 - x < 1e-15, "next_float_monotonic: delta = {:?}", x1 - x); - x = x1; - } - assert!(x > 0.5); -} - -#[test] -fn test_f32_integer_decode() { - assert_eq!(3.14159265359f32.integer_decode(), (13176795, -22, 1)); - assert_eq!((-8573.5918555f32).integer_decode(), (8779358, -10, -1)); - assert_eq!(2f32.powf(100.0).integer_decode(), (8388608, 77, 1)); - assert_eq!(0f32.integer_decode(), (0, -150, 1)); - assert_eq!((-0f32).integer_decode(), (0, -150, -1)); - assert_eq!(f32::INFINITY.integer_decode(), (8388608, 105, 1)); - assert_eq!(f32::NEG_INFINITY.integer_decode(), (8388608, 105, -1)); - - // Ignore the "sign" (quiet / signalling flag) of NAN. - // It can vary between runtime operations and LLVM folding. - let (nan_m, nan_e, _nan_s) = f32::NAN.integer_decode(); - assert_eq!((nan_m, nan_e), (12582912, 105)); -} - -#[test] -fn test_f64_integer_decode() { - assert_eq!(3.14159265359f64.integer_decode(), (7074237752028906, -51, 1)); - assert_eq!((-8573.5918555f64).integer_decode(), (4713381968463931, -39, -1)); - assert_eq!(2f64.powf(100.0).integer_decode(), (4503599627370496, 48, 1)); - assert_eq!(0f64.integer_decode(), (0, -1075, 1)); - assert_eq!((-0f64).integer_decode(), (0, -1075, -1)); - assert_eq!(f64::INFINITY.integer_decode(), (4503599627370496, 972, 1)); - assert_eq!(f64::NEG_INFINITY.integer_decode(), (4503599627370496, 972, -1)); - - // Ignore the "sign" (quiet / signalling flag) of NAN. - // It can vary between runtime operations and LLVM folding. - let (nan_m, nan_e, _nan_s) = f64::NAN.integer_decode(); - assert_eq!((nan_m, nan_e), (6755399441055744, 972)); -} diff --git a/library/core/tests/num/flt2dec/mod.rs b/library/core/tests/num/flt2dec/mod.rs index 960a7ca5ff5..4874e8ec09f 100644 --- a/library/core/tests/num/flt2dec/mod.rs +++ b/library/core/tests/num/flt2dec/mod.rs @@ -2,10 +2,11 @@ use std::mem::MaybeUninit; use std::{fmt, str}; use core::num::flt2dec::{decode, DecodableFloat, Decoded, FullDecoded}; -use core::num::flt2dec::{round_up, Formatted, Part, Sign, MAX_SIG_DIGITS}; +use core::num::flt2dec::{round_up, Sign, MAX_SIG_DIGITS}; use core::num::flt2dec::{ to_exact_exp_str, to_exact_fixed_str, to_shortest_exp_str, to_shortest_str, }; +use core::num::fmt::{Formatted, Part}; pub use test::Bencher; diff --git a/library/core/tests/num/int_log.rs b/library/core/tests/num/int_log.rs new file mode 100644 index 00000000000..51122c11ce1 --- /dev/null +++ b/library/core/tests/num/int_log.rs @@ -0,0 +1,153 @@ +//! This tests the `Integer::{log,log2,log10}` methods. These tests are in a +//! separate file because there's both a large number of them, and not all tests +//! can be run on Android. This is because in Android `log2` uses an imprecise +//! approximation:https://github.com/rust-lang/rust/blob/4825e12fc9c79954aa0fe18f5521efa6c19c7539/src/libstd/sys/unix/android.rs#L27-L53 + +#[test] +fn checked_log() { + assert_eq!(999u32.checked_log(10), Some(2)); + assert_eq!(1000u32.checked_log(10), Some(3)); + assert_eq!(555u32.checked_log(13), Some(2)); + assert_eq!(63u32.checked_log(4), Some(2)); + assert_eq!(64u32.checked_log(4), Some(3)); + assert_eq!(10460353203u64.checked_log(3), Some(21)); + assert_eq!(10460353202u64.checked_log(3), Some(20)); + assert_eq!(147808829414345923316083210206383297601u128.checked_log(3), Some(80)); + assert_eq!(147808829414345923316083210206383297600u128.checked_log(3), Some(79)); + assert_eq!(22528399544939174411840147874772641u128.checked_log(19683), Some(8)); + assert_eq!(22528399544939174411840147874772631i128.checked_log(19683), Some(7)); + + assert_eq!(0u8.checked_log(4), None); + assert_eq!(0u16.checked_log(4), None); + assert_eq!(0i8.checked_log(4), None); + assert_eq!(0i16.checked_log(4), None); + + for i in i16::MIN..=0 { + assert_eq!(i.checked_log(4), None); + } + for i in 1..=i16::MAX { + assert_eq!(i.checked_log(13), Some((i as f32).log(13.0) as i16)); + } + for i in 1..=u16::MAX { + assert_eq!(i.checked_log(13), Some((i as f32).log(13.0) as u16)); + } +} + +#[test] +fn checked_log2() { + assert_eq!(5u32.checked_log2(), Some(2)); + assert_eq!(0u64.checked_log2(), None); + assert_eq!(128i32.checked_log2(), Some(7)); + assert_eq!((-55i16).checked_log2(), None); + + assert_eq!(0u8.checked_log2(), None); + assert_eq!(0u16.checked_log2(), None); + assert_eq!(0i8.checked_log2(), None); + assert_eq!(0i16.checked_log2(), None); + + for i in 1..=u8::MAX { + assert_eq!(i.checked_log2(), Some((i as f32).log2() as u8)); + } + for i in 1..=u16::MAX { + // Guard against Android's imprecise f32::log2 implementation. + if i != 8192 && i != 32768 { + assert_eq!(i.checked_log2(), Some((i as f32).log2() as u16)); + } + } + for i in i8::MIN..=0 { + assert_eq!(i.checked_log2(), None); + } + for i in 1..=i8::MAX { + assert_eq!(i.checked_log2(), Some((i as f32).log2() as i8)); + } + for i in i16::MIN..=0 { + assert_eq!(i.checked_log2(), None); + } + for i in 1..=i16::MAX { + // Guard against Android's imprecise f32::log2 implementation. + if i != 8192 { + assert_eq!(i.checked_log2(), Some((i as f32).log2() as i16)); + } + } +} + +// Validate cases that fail on Android's imprecise float log2 implementation. +#[test] +#[cfg(not(target_os = "android"))] +fn checked_log2_not_android() { + assert_eq!(8192u16.checked_log2(), Some((8192f32).log2() as u16)); + assert_eq!(32768u16.checked_log2(), Some((32768f32).log2() as u16)); + assert_eq!(8192i16.checked_log2(), Some((8192f32).log2() as i16)); +} + +#[test] +fn checked_log10() { + assert_eq!(0u8.checked_log10(), None); + assert_eq!(0u16.checked_log10(), None); + assert_eq!(0i8.checked_log10(), None); + assert_eq!(0i16.checked_log10(), None); + + for i in i16::MIN..=0 { + assert_eq!(i.checked_log10(), None); + } + for i in 1..=i16::MAX { + assert_eq!(i.checked_log10(), Some((i as f32).log10() as i16)); + } + for i in 1..=u16::MAX { + assert_eq!(i.checked_log10(), Some((i as f32).log10() as u16)); + } +} + +macro_rules! log10_loop { + ($T:ty, $log10_max:expr) => { + assert_eq!(<$T>::MAX.log10(), $log10_max); + for i in 0..=$log10_max { + let p = (10 as $T).pow(i as u32); + if p >= 10 { + assert_eq!((p - 9).log10(), i - 1); + assert_eq!((p - 1).log10(), i - 1); + } + assert_eq!(p.log10(), i); + assert_eq!((p + 1).log10(), i); + if p >= 10 { + assert_eq!((p + 9).log10(), i); + } + + // also check `x.log(10)` + if p >= 10 { + assert_eq!((p - 9).log(10), i - 1); + assert_eq!((p - 1).log(10), i - 1); + } + assert_eq!(p.log(10), i); + assert_eq!((p + 1).log(10), i); + if p >= 10 { + assert_eq!((p + 9).log(10), i); + } + } + }; +} + +#[test] +fn log10_u8() { + log10_loop! { u8, 2 } +} + +#[test] +fn log10_u16() { + log10_loop! { u16, 4 } +} + +#[test] +fn log10_u32() { + log10_loop! { u32, 9 } +} + +#[test] +fn log10_u64() { + log10_loop! { u64, 19 } +} + +#[test] +fn log10_u128() { + log10_loop! { u128, 38 } +} diff --git a/library/core/tests/num/mod.rs b/library/core/tests/num/mod.rs index bbb67667dfc..37b5e9127d5 100644 --- a/library/core/tests/num/mod.rs +++ b/library/core/tests/num/mod.rs @@ -27,8 +27,11 @@ mod u64; mod u8; mod bignum; + +mod const_from; mod dec2flt; mod flt2dec; +mod int_log; mod ops; mod wrapping; diff --git a/library/core/tests/option.rs b/library/core/tests/option.rs index 88ea15a3b33..cd8fdebe36a 100644 --- a/library/core/tests/option.rs +++ b/library/core/tests/option.rs @@ -399,7 +399,7 @@ fn test_unwrap_drop() { } #[test] -pub fn option_ext() { +fn option_ext() { let thing = "{{ f }}"; let f = thing.find("{{"); @@ -407,3 +407,35 @@ pub fn option_ext() { println!("None!"); } } + +#[test] +fn zip_options() { + let x = Some(10); + let y = Some("foo"); + let z: Option<usize> = None; + + assert_eq!(x.zip(y), Some((10, "foo"))); + assert_eq!(x.zip(z), None); + assert_eq!(z.zip(x), None); +} + +#[test] +fn unzip_options() { + let x = Some((10, "foo")); + let y = None::<(bool, i32)>; + + assert_eq!(x.unzip(), (Some(10), Some("foo"))); + assert_eq!(y.unzip(), (None, None)); +} + +#[test] +fn zip_unzip_roundtrip() { + let x = Some(10); + let y = Some("foo"); + + let z = x.zip(y); + assert_eq!(z, Some((10, "foo"))); + + let a = z.unzip(); + assert_eq!(a, (x, y)); +} diff --git a/library/core/tests/result.rs b/library/core/tests/result.rs index f4e5e7751b8..612f083a5c1 100644 --- a/library/core/tests/result.rs +++ b/library/core/tests/result.rs @@ -391,7 +391,6 @@ fn result_opt_conversions() { } #[test] -#[cfg(not(bootstrap))] // Needs the V2 trait fn result_try_trait_v2_branch() { use core::num::NonZeroU32; use core::ops::{ControlFlow::*, Try}; diff --git a/library/core/tests/slice.rs b/library/core/tests/slice.rs index 3a98cd9d2ee..43e2af3eb18 100644 --- a/library/core/tests/slice.rs +++ b/library/core/tests/slice.rs @@ -135,6 +135,48 @@ fn test_partition_point() { } #[test] +fn test_iterator_advance_by() { + let v = &[0, 1, 2, 3, 4]; + + for i in 0..=v.len() { + let mut iter = v.iter(); + iter.advance_by(i).unwrap(); + assert_eq!(iter.as_slice(), &v[i..]); + } + + let mut iter = v.iter(); + assert_eq!(iter.advance_by(v.len() + 1), Err(v.len())); + assert_eq!(iter.as_slice(), &[]); + + let mut iter = v.iter(); + iter.advance_by(3).unwrap(); + assert_eq!(iter.as_slice(), &v[3..]); + iter.advance_by(2).unwrap(); + assert_eq!(iter.as_slice(), &[]); +} + +#[test] +fn test_iterator_advance_back_by() { + let v = &[0, 1, 2, 3, 4]; + + for i in 0..=v.len() { + let mut iter = v.iter(); + iter.advance_back_by(i).unwrap(); + assert_eq!(iter.as_slice(), &v[..v.len() - i]); + } + + let mut iter = v.iter(); + assert_eq!(iter.advance_back_by(v.len() + 1), Err(v.len())); + assert_eq!(iter.as_slice(), &[]); + + let mut iter = v.iter(); + iter.advance_back_by(3).unwrap(); + assert_eq!(iter.as_slice(), &v[..v.len() - 3]); + iter.advance_back_by(2).unwrap(); + assert_eq!(iter.as_slice(), &[]); +} + +#[test] fn test_iterator_nth() { let v: &[_] = &[0, 1, 2, 3, 4]; for i in 0..v.len() { @@ -697,6 +739,10 @@ fn test_array_windows_count() { let v3: &[i32] = &[]; let c3 = v3.array_windows::<2>(); assert_eq!(c3.count(), 0); + + let v4: &[()] = &[(); usize::MAX]; + let c4 = v4.array_windows::<1>(); + assert_eq!(c4.count(), usize::MAX); } #[test] @@ -1008,6 +1054,10 @@ fn test_windows_count() { let v3: &[i32] = &[]; let c3 = v3.windows(2); assert_eq!(c3.count(), 0); + + let v4 = &[(); usize::MAX]; + let c4 = v4.windows(1); + assert_eq!(c4.count(), usize::MAX); } #[test] diff --git a/library/panic_abort/Cargo.toml b/library/panic_abort/Cargo.toml index bdab664cd64..6dec0e67497 100644 --- a/library/panic_abort/Cargo.toml +++ b/library/panic_abort/Cargo.toml @@ -1,5 +1,4 @@ [package] -authors = ["The Rust Project Developers"] name = "panic_abort" version = "0.0.0" license = "MIT OR Apache-2.0" diff --git a/library/panic_abort/src/android.rs b/library/panic_abort/src/android.rs index 34d77502eab..18bb932f10e 100644 --- a/library/panic_abort/src/android.rs +++ b/library/panic_abort/src/android.rs @@ -7,7 +7,7 @@ const ANDROID_SET_ABORT_MESSAGE: &[u8] = b"android_set_abort_message\0"; type SetAbortMessageType = unsafe extern "C" fn(*const libc::c_char) -> (); // Forward the abort message to libc's android_set_abort_message. We try our best to populate the -// message but as this function may already be called as part of a failed allocation, it may not be +// message but as this function may already be called as part of a failed allocation, it might not be // possible to do so. // // Some methods of core are on purpose avoided (such as try_reserve) as these rely on the correct diff --git a/library/panic_abort/src/lib.rs b/library/panic_abort/src/lib.rs index d95ea6530c2..4580f9a7758 100644 --- a/library/panic_abort/src/lib.rs +++ b/library/panic_abort/src/lib.rs @@ -15,6 +15,7 @@ #![feature(staged_api)] #![feature(rustc_attrs)] #![feature(asm)] +#![feature(c_unwind)] #[cfg(target_os = "android")] mod android; @@ -30,7 +31,7 @@ pub unsafe extern "C" fn __rust_panic_cleanup(_: *mut u8) -> *mut (dyn Any + Sen // "Leak" the payload and shim to the relevant abort on the platform in question. #[rustc_std_internal_symbol] -pub unsafe extern "C" fn __rust_start_panic(_payload: *mut &mut dyn BoxMeUp) -> u32 { +pub unsafe extern "C-unwind" fn __rust_start_panic(_payload: *mut &mut dyn BoxMeUp) -> u32 { // Android has the ability to attach a message as part of the abort. #[cfg(target_os = "android")] android::android_set_abort_message(_payload); diff --git a/library/panic_unwind/Cargo.toml b/library/panic_unwind/Cargo.toml index 533f059a85e..67405463aa6 100644 --- a/library/panic_unwind/Cargo.toml +++ b/library/panic_unwind/Cargo.toml @@ -1,5 +1,4 @@ [package] -authors = ["The Rust Project Developers"] name = "panic_unwind" version = "0.0.0" license = "MIT OR Apache-2.0" diff --git a/library/panic_unwind/src/dwarf/eh.rs b/library/panic_unwind/src/dwarf/eh.rs index 6dbf7c11b4c..7394feab82f 100644 --- a/library/panic_unwind/src/dwarf/eh.rs +++ b/library/panic_unwind/src/dwarf/eh.rs @@ -1,9 +1,9 @@ //! Parsing of GCC-style Language-Specific Data Area (LSDA) //! For details see: -//! * <http://refspecs.linuxfoundation.org/LSB_3.0.0/LSB-PDA/LSB-PDA/ehframechpt.html> -//! * <http://mentorembedded.github.io/cxx-abi/exceptions.pdf> -//! * <http://www.airs.com/blog/archives/460> -//! * <http://www.airs.com/blog/archives/464> +//! * <https://refspecs.linuxfoundation.org/LSB_3.0.0/LSB-PDA/LSB-PDA/ehframechpt.html> +//! * <https://itanium-cxx-abi.github.io/cxx-abi/exceptions.pdf> +//! * <https://www.airs.com/blog/archives/460> +//! * <https://www.airs.com/blog/archives/464> //! //! A reference implementation may be found in the GCC source tree //! (`<root>/libgcc/unwind-c.c` as of this writing). diff --git a/library/panic_unwind/src/gcc.rs b/library/panic_unwind/src/gcc.rs index 14f49bbf483..9d6ede73e3d 100644 --- a/library/panic_unwind/src/gcc.rs +++ b/library/panic_unwind/src/gcc.rs @@ -5,8 +5,8 @@ //! documents linked from it. //! These are also good reads: //! * <https://itanium-cxx-abi.github.io/cxx-abi/abi-eh.html> -//! * <http://monoinfinito.wordpress.com/series/exception-handling-in-c/> -//! * <http://www.airs.com/blog/index.php?s=exception+frames> +//! * <https://monoinfinito.wordpress.com/series/exception-handling-in-c/> +//! * <https://www.airs.com/blog/index.php?s=exception+frames> //! //! ## A brief summary //! @@ -94,7 +94,7 @@ fn rust_exception_class() -> uw::_Unwind_Exception_Class { // and TargetLowering::getExceptionSelectorRegister() for each architecture, // then mapped to DWARF register numbers via register definition tables // (typically <arch>RegisterInfo.td, search for "DwarfRegNum"). -// See also http://llvm.org/docs/WritingAnLLVMBackend.html#defining-a-register. +// See also https://llvm.org/docs/WritingAnLLVMBackend.html#defining-a-register. #[cfg(target_arch = "x86")] const UNWIND_DATA_REG: (i32, i32) = (0, 2); // EAX, EDX @@ -130,7 +130,7 @@ const UNWIND_DATA_REG: (i32, i32) = (10, 11); // x10, x11 cfg_if::cfg_if! { if #[cfg(all(target_arch = "arm", not(target_os = "ios"), not(target_os = "netbsd")))] { // ARM EHABI personality routine. - // http://infocenter.arm.com/help/topic/com.arm.doc.ihi0038b/IHI0038B_ehabi.pdf + // https://infocenter.arm.com/help/topic/com.arm.doc.ihi0038b/IHI0038B_ehabi.pdf // // iOS uses the default routine instead since it uses SjLj unwinding. #[lang = "eh_personality"] diff --git a/library/panic_unwind/src/lib.rs b/library/panic_unwind/src/lib.rs index d32a3f1f832..ac7d8c18e3e 100644 --- a/library/panic_unwind/src/lib.rs +++ b/library/panic_unwind/src/lib.rs @@ -20,12 +20,11 @@ #![feature(panic_unwind)] #![feature(staged_api)] #![feature(std_internals)] -#![feature(unwind_attributes)] #![feature(abi_thiscall)] #![feature(rustc_attrs)] -#![feature(raw)] #![panic_runtime] #![feature(panic_runtime)] +#![feature(c_unwind)] // `real_imp` is unused with Miri, so silence warnings. #![cfg_attr(miri, allow(dead_code))] @@ -46,7 +45,7 @@ cfg_if::cfg_if! { } else if #[cfg(any( all(target_family = "windows", target_env = "gnu"), target_os = "psp", - target_family = "unix", + all(target_family = "unix", not(target_os = "espidf")), all(target_vendor = "fortanix", target_env = "sgx"), ))] { // Rust runtime's startup objects depend on these symbols, so make them public. @@ -59,6 +58,7 @@ cfg_if::cfg_if! { // - arch=wasm32 // - os=none ("bare metal" targets) // - os=uefi + // - os=espidf // - nvptx64-nvidia-cuda // - arch=avr #[path = "dummy.rs"] @@ -99,8 +99,7 @@ pub unsafe extern "C" fn __rust_panic_cleanup(payload: *mut u8) -> *mut (dyn Any // Entry point for raising an exception, just delegates to the platform-specific // implementation. #[rustc_std_internal_symbol] -#[unwind(allowed)] -pub unsafe extern "C" fn __rust_start_panic(payload: *mut &mut dyn BoxMeUp) -> u32 { +pub unsafe extern "C-unwind" fn __rust_start_panic(payload: *mut &mut dyn BoxMeUp) -> u32 { let payload = Box::from_raw((*payload).take_box()); imp::panic(payload) diff --git a/library/panic_unwind/src/seh.rs b/library/panic_unwind/src/seh.rs index 58028d40576..9f1eb411ff6 100644 --- a/library/panic_unwind/src/seh.rs +++ b/library/panic_unwind/src/seh.rs @@ -42,7 +42,7 @@ //! of the `try` intrinsic. //! //! [win64]: https://docs.microsoft.com/en-us/cpp/build/exception-handling-x64 -//! [llvm]: http://llvm.org/docs/ExceptionHandling.html#background-on-windows-exceptions +//! [llvm]: https://llvm.org/docs/ExceptionHandling.html#background-on-windows-exceptions #![allow(nonstandard_style)] @@ -100,7 +100,7 @@ struct Exception { // In any case, these structures are all constructed in a similar manner, and // it's just somewhat verbose for us. // -// [1]: http://www.geoffchappell.com/studies/msvc/language/predefined/ +// [1]: https://www.geoffchappell.com/studies/msvc/language/predefined/ #[cfg(target_arch = "x86")] #[macro_use] @@ -233,15 +233,14 @@ static mut TYPE_DESCRIPTOR: _TypeDescriptor = _TypeDescriptor { // support capturing exceptions with std::exception_ptr, which we can't support // because Box<dyn Any> isn't clonable. macro_rules! define_cleanup { - ($abi:tt) => { + ($abi:tt $abi2:tt) => { unsafe extern $abi fn exception_cleanup(e: *mut Exception) { if let Exception { data: Some(b) } = e.read() { drop(b); super::__rust_drop_panic(); } } - #[unwind(allowed)] - unsafe extern $abi fn exception_copy(_dest: *mut Exception, + unsafe extern $abi2 fn exception_copy(_dest: *mut Exception, _src: *mut Exception) -> *mut Exception { panic!("Rust panics cannot be copied"); @@ -250,9 +249,9 @@ macro_rules! define_cleanup { } cfg_if::cfg_if! { if #[cfg(target_arch = "x86")] { - define_cleanup!("thiscall"); + define_cleanup!("thiscall" "thiscall-unwind"); } else { - define_cleanup!("C"); + define_cleanup!("C" "C-unwind"); } } @@ -307,8 +306,7 @@ pub unsafe fn panic(data: Box<dyn Any + Send>) -> u32 { ptr!(exception_copy) as u32, ); - extern "system" { - #[unwind(allowed)] + extern "system-unwind" { fn _CxxThrowException(pExceptionObject: *mut c_void, pThrowInfo: *mut u8) -> !; } diff --git a/library/proc_macro/Cargo.toml b/library/proc_macro/Cargo.toml index 9cc9ef4ec19..faf460e32bd 100644 --- a/library/proc_macro/Cargo.toml +++ b/library/proc_macro/Cargo.toml @@ -1,5 +1,4 @@ [package] -authors = ["The Rust Project Developers"] name = "proc_macro" version = "0.0.0" edition = "2018" diff --git a/library/proc_macro/src/bridge/buffer.rs b/library/proc_macro/src/bridge/buffer.rs index 717201aef10..d82669d3e23 100644 --- a/library/proc_macro/src/bridge/buffer.rs +++ b/library/proc_macro/src/bridge/buffer.rs @@ -6,35 +6,6 @@ use std::ops::{Deref, DerefMut}; use std::slice; #[repr(C)] -struct Slice<'a, T> { - data: &'a [T; 0], - len: usize, -} - -unsafe impl<'a, T: Sync> Sync for Slice<'a, T> {} -unsafe impl<'a, T: Sync> Send for Slice<'a, T> {} - -impl<T> Copy for Slice<'a, T> {} -impl<T> Clone for Slice<'a, T> { - fn clone(&self) -> Self { - *self - } -} - -impl<T> From<&'a [T]> for Slice<'a, T> { - fn from(xs: &'a [T]) -> Self { - Slice { data: unsafe { &*(xs.as_ptr() as *const [T; 0]) }, len: xs.len() } - } -} - -impl<T> Deref for Slice<'a, T> { - type Target = [T]; - fn deref(&self) -> &[T] { - unsafe { slice::from_raw_parts(self.data.as_ptr(), self.len) } - } -} - -#[repr(C)] pub struct Buffer<T: Copy> { data: *mut T, len: usize, diff --git a/library/proc_macro/src/bridge/client.rs b/library/proc_macro/src/bridge/client.rs index c6bec5a6fbd..8ae7b6de1a6 100644 --- a/library/proc_macro/src/bridge/client.rs +++ b/library/proc_macro/src/bridge/client.rs @@ -386,7 +386,7 @@ fn run_client<A: for<'a, 's> DecodeMut<'a, 's, ()>, R: Encode<()>>( // // Note that panics should be impossible beyond this point, but // this is defensively trying to avoid any accidental panicking - // reaching the `extern "C"` (which should `abort` but may not + // reaching the `extern "C"` (which should `abort` but might not // at the moment, so this is also potentially preventing UB). b.clear(); Ok::<_, ()>(output).encode(&mut b, &mut ()); diff --git a/library/proc_macro/src/bridge/mod.rs b/library/proc_macro/src/bridge/mod.rs index a2953b68564..7001e827ad8 100644 --- a/library/proc_macro/src/bridge/mod.rs +++ b/library/proc_macro/src/bridge/mod.rs @@ -55,6 +55,7 @@ macro_rules! with_api { FreeFunctions { fn drop($self: $S::FreeFunctions); fn track_env_var(var: &str, value: Option<&str>); + fn track_path(path: &str); }, TokenStream { fn drop($self: $S::TokenStream); @@ -108,6 +109,7 @@ macro_rules! with_api { fn drop($self: $S::Literal); fn clone($self: &$S::Literal) -> $S::Literal; fn from_str(s: &str) -> Result<$S::Literal, ()>; + fn to_string($self: &$S::Literal) -> String; fn debug_kind($self: &$S::Literal) -> String; fn symbol($self: &$S::Literal) -> String; fn suffix($self: &$S::Literal) -> Option<String>; diff --git a/library/proc_macro/src/bridge/rpc.rs b/library/proc_macro/src/bridge/rpc.rs index 588e6ded0f4..42432563faf 100644 --- a/library/proc_macro/src/bridge/rpc.rs +++ b/library/proc_macro/src/bridge/rpc.rs @@ -246,7 +246,7 @@ impl<S> DecodeMut<'_, '_, S> for String { } } -/// Simplied version of panic payloads, ignoring +/// Simplified version of panic payloads, ignoring /// types other than `&'static str` and `String`. pub enum PanicMessage { StaticStr(&'static str), diff --git a/library/proc_macro/src/diagnostic.rs b/library/proc_macro/src/diagnostic.rs index 7495468a05b..6e46dc0367d 100644 --- a/library/proc_macro/src/diagnostic.rs +++ b/library/proc_macro/src/diagnostic.rs @@ -56,10 +56,9 @@ pub struct Diagnostic { macro_rules! diagnostic_child_methods { ($spanned:ident, $regular:ident, $level:expr) => { - /// Adds a new child diagnostic message to `self` with the level - /// identified by this method's name with the given `spans` and - /// `message`. #[unstable(feature = "proc_macro_diagnostic", issue = "54140")] + #[doc = concat!("Adds a new child diagnostics message to `self` with the [`", + stringify!($level), "`] level, and the given `spans` and `message`.")] pub fn $spanned<S, T>(mut self, spans: S, message: T) -> Diagnostic where S: MultiSpan, @@ -69,9 +68,9 @@ macro_rules! diagnostic_child_methods { self } - /// Adds a new child diagnostic message to `self` with the level - /// identified by this method's name with the given `message`. #[unstable(feature = "proc_macro_diagnostic", issue = "54140")] + #[doc = concat!("Adds a new child diagnostic message to `self` with the [`", + stringify!($level), "`] level, and the given `message`.")] pub fn $regular<T: Into<String>>(mut self, message: T) -> Diagnostic { self.children.push(Diagnostic::new($level, message)); self diff --git a/library/proc_macro/src/lib.rs b/library/proc_macro/src/lib.rs index 3990826ce42..f25e257bf31 100644 --- a/library/proc_macro/src/lib.rs +++ b/library/proc_macro/src/lib.rs @@ -43,7 +43,7 @@ mod diagnostic; pub use diagnostic::{Diagnostic, Level, MultiSpan}; use std::cmp::Ordering; -use std::ops::{Bound, RangeBounds}; +use std::ops::RangeBounds; use std::path::PathBuf; use std::str::FromStr; use std::{error, fmt, iter, mem}; @@ -84,14 +84,13 @@ impl !Sync for TokenStream {} /// Error returned from `TokenStream::from_str`. #[stable(feature = "proc_macro_lib", since = "1.15.0")] +#[non_exhaustive] #[derive(Debug)] -pub struct LexError { - _inner: (), -} +pub struct LexError; impl LexError { fn new() -> Self { - LexError { _inner: () } + LexError } } @@ -349,13 +348,13 @@ impl Span { /// Gets the starting line/column in the source file for this span. #[unstable(feature = "proc_macro_span", issue = "54725")] pub fn start(&self) -> LineColumn { - self.0.start() + self.0.start().add_1_to_column() } /// Gets the ending line/column in the source file for this span. #[unstable(feature = "proc_macro_span", issue = "54725")] pub fn end(&self) -> LineColumn { - self.0.end() + self.0.end().add_1_to_column() } /// Creates a new span encompassing `self` and `other`. @@ -433,12 +432,18 @@ pub struct LineColumn { /// The 1-indexed line in the source file on which the span starts or ends (inclusive). #[unstable(feature = "proc_macro_span", issue = "54725")] pub line: usize, - /// The 0-indexed column (in UTF-8 characters) in the source file on which - /// the span starts or ends (inclusive). + /// The 1-indexed column (number of bytes in UTF-8 encoding) in the source + /// file on which the span starts or ends (inclusive). #[unstable(feature = "proc_macro_span", issue = "54725")] pub column: usize, } +impl LineColumn { + fn add_1_to_column(self) -> Self { + LineColumn { line: self.line, column: self.column + 1 } + } +} + #[unstable(feature = "proc_macro_span", issue = "54725")] impl !Send for LineColumn {} #[unstable(feature = "proc_macro_span", issue = "54725")] @@ -468,10 +473,10 @@ impl SourceFile { /// /// ### Note /// If the code span associated with this `SourceFile` was generated by an external macro, this - /// macro, this may not be an actual path on the filesystem. Use [`is_real`] to check. + /// macro, this might not be an actual path on the filesystem. Use [`is_real`] to check. /// /// Also note that even if `is_real` returns `true`, if `--remap-path-prefix` was passed on - /// the command line, the path as given may not actually be valid. + /// the command line, the path as given might not actually be valid. /// /// [`is_real`]: Self::is_real #[unstable(feature = "proc_macro_span", issue = "54725")] @@ -658,7 +663,7 @@ pub enum Delimiter { /// An implicit delimiter, that may, for example, appear around tokens coming from a /// "macro variable" `$var`. It is important to preserve operator priorities in cases like /// `$var * 3` where `$var` is `1 + 2`. - /// Implicit delimiters may not survive roundtrip of a token stream through a string. + /// Implicit delimiters might not survive roundtrip of a token stream through a string. #[stable(feature = "proc_macro_lib2", since = "1.29.0")] None, } @@ -707,7 +712,7 @@ impl Group { /// pub fn span_open(&self) -> Span { /// ^ /// ``` - #[unstable(feature = "proc_macro_span", issue = "54725")] + #[stable(feature = "proc_macro_group_span", since = "1.55.0")] pub fn span_open(&self) -> Span { Span(self.0.span_open()) } @@ -718,7 +723,7 @@ impl Group { /// pub fn span_close(&self) -> Span { /// ^ /// ``` - #[unstable(feature = "proc_macro_span", issue = "54725")] + #[stable(feature = "proc_macro_group_span", since = "1.55.0")] pub fn span_close(&self) -> Span { Span(self.0.span_close()) } @@ -765,7 +770,7 @@ impl fmt::Debug for Group { } } -/// An `Punct` is an single punctuation character like `+`, `-` or `#`. +/// A `Punct` is a single punctuation character such as `+`, `-` or `#`. /// /// Multi-character operators like `+=` are represented as two instances of `Punct` with different /// forms of `Spacing` returned. @@ -778,16 +783,19 @@ impl !Send for Punct {} #[stable(feature = "proc_macro_lib2", since = "1.29.0")] impl !Sync for Punct {} -/// Whether an `Punct` is followed immediately by another `Punct` or -/// followed by another token or whitespace. +/// Describes whether a `Punct` is followed immediately by another `Punct` ([`Spacing::Joint`]) or +/// by a different token or whitespace ([`Spacing::Alone`]). #[derive(Copy, Clone, Debug, PartialEq, Eq)] #[stable(feature = "proc_macro_lib2", since = "1.29.0")] pub enum Spacing { - /// e.g., `+` is `Alone` in `+ =`, `+ident` or `+()`. + /// A `Punct` is not immediately followed by another `Punct`. + /// E.g. `+` is `Alone` in `+ =`, `+ident` and `+()`. #[stable(feature = "proc_macro_lib2", since = "1.29.0")] Alone, - /// e.g., `+` is `Joint` in `+=` or `'#`. - /// Additionally, single quote `'` can join with identifiers to form lifetimes `'ident`. + /// A `Punct` is immediately followed by another `Punct`. + /// E.g. `+` is `Joint` in `+=` and `++`. + /// + /// Additionally, single quote `'` can join with identifiers to form lifetimes: `'ident`. #[stable(feature = "proc_macro_lib2", since = "1.29.0")] Joint, } @@ -971,7 +979,7 @@ macro_rules! suffixed_int_literals { /// This function will create an integer like `1u32` where the integer /// value specified is the first part of the token and the integral is /// also suffixed at the end. - /// Literals created from negative numbers may not survive round-trips through + /// Literals created from negative numbers might not survive round-trips through /// `TokenStream` or strings and may be broken into two tokens (`-` and positive literal). /// /// Literals created through this method have the `Span::call_site()` @@ -993,7 +1001,7 @@ macro_rules! unsuffixed_int_literals { /// specified on this token, meaning that invocations like /// `Literal::i8_unsuffixed(1)` are equivalent to /// `Literal::u32_unsuffixed(1)`. - /// Literals created from negative numbers may not survive rountrips through + /// Literals created from negative numbers might not survive rountrips through /// `TokenStream` or strings and may be broken into two tokens (`-` and positive literal). /// /// Literals created through this method have the `Span::call_site()` @@ -1042,7 +1050,7 @@ impl Literal { /// This constructor is similar to those like `Literal::i8_unsuffixed` where /// the float's value is emitted directly into the token but no suffix is /// used, so it may be inferred to be a `f64` later in the compiler. - /// Literals created from negative numbers may not survive rountrips through + /// Literals created from negative numbers might not survive rountrips through /// `TokenStream` or strings and may be broken into two tokens (`-` and positive literal). /// /// # Panics @@ -1063,7 +1071,7 @@ impl Literal { /// specified is the preceding part of the token and `f32` is the suffix of /// the token. This token will always be inferred to be an `f32` in the /// compiler. - /// Literals created from negative numbers may not survive rountrips through + /// Literals created from negative numbers might not survive rountrips through /// `TokenStream` or strings and may be broken into two tokens (`-` and positive literal). /// /// # Panics @@ -1083,7 +1091,7 @@ impl Literal { /// This constructor is similar to those like `Literal::i8_unsuffixed` where /// the float's value is emitted directly into the token but no suffix is /// used, so it may be inferred to be a `f64` later in the compiler. - /// Literals created from negative numbers may not survive rountrips through + /// Literals created from negative numbers might not survive rountrips through /// `TokenStream` or strings and may be broken into two tokens (`-` and positive literal). /// /// # Panics @@ -1104,7 +1112,7 @@ impl Literal { /// specified is the preceding part of the token and `f64` is the suffix of /// the token. This token will always be inferred to be an `f64` in the /// compiler. - /// Literals created from negative numbers may not survive rountrips through + /// Literals created from negative numbers might not survive rountrips through /// `TokenStream` or strings and may be broken into two tokens (`-` and positive literal). /// /// # Panics @@ -1162,16 +1170,7 @@ impl Literal { // was 'c' or whether it was '\u{63}'. #[unstable(feature = "proc_macro_span", issue = "54725")] pub fn subspan<R: RangeBounds<usize>>(&self, range: R) -> Option<Span> { - // HACK(eddyb) something akin to `Option::cloned`, but for `Bound<&T>`. - fn cloned_bound<T: Clone>(bound: Bound<&T>) -> Bound<T> { - match bound { - Bound::Included(x) => Bound::Included(x.clone()), - Bound::Excluded(x) => Bound::Excluded(x.clone()), - Bound::Unbounded => Bound::Unbounded, - } - } - - self.0.subspan(cloned_bound(range.start_bound()), cloned_bound(range.end_bound())).map(Span) + self.0.subspan(range.start_bound().cloned(), range.end_bound().cloned()).map(Span) } } @@ -1202,7 +1201,7 @@ impl FromStr for Literal { #[stable(feature = "proc_macro_lib", since = "1.15.0")] impl ToString for Literal { fn to_string(&self) -> String { - TokenStream::from(TokenTree::from(self.clone())).to_string() + self.0.to_string() } } @@ -1241,3 +1240,17 @@ pub mod tracked_env { value } } + +/// Tracked access to additional files. +#[unstable(feature = "track_path", issue = "73921")] +pub mod tracked_path { + + /// Track a file explicitly. + /// + /// Commonly used for tracking asset preprocessing. + #[unstable(feature = "track_path", issue = "73921")] + pub fn path<P: AsRef<str>>(path: P) { + let path: &str = path.as_ref(); + crate::bridge::client::FreeFunctions::track_path(path); + } +} diff --git a/library/profiler_builtins/Cargo.toml b/library/profiler_builtins/Cargo.toml index 7b7ca8029b4..0f7f0067652 100644 --- a/library/profiler_builtins/Cargo.toml +++ b/library/profiler_builtins/Cargo.toml @@ -1,5 +1,4 @@ [package] -authors = ["The Rust Project Developers"] name = "profiler_builtins" version = "0.0.0" edition = "2018" @@ -14,4 +13,4 @@ core = { path = "../core" } compiler_builtins = { version = "0.1.0", features = ['rustc-dep-of-std'] } [build-dependencies] -cc = "1.0.68" +cc = "1.0.69" diff --git a/library/rustc-std-workspace-alloc/Cargo.toml b/library/rustc-std-workspace-alloc/Cargo.toml index 810197afd31..1ea421834a7 100644 --- a/library/rustc-std-workspace-alloc/Cargo.toml +++ b/library/rustc-std-workspace-alloc/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "rustc-std-workspace-alloc" version = "1.99.0" -authors = ["Alex Crichton <alex@alexcrichton.com>"] license = 'MIT OR Apache-2.0' description = """ Hack for the compiler's own build system diff --git a/library/rustc-std-workspace-core/Cargo.toml b/library/rustc-std-workspace-core/Cargo.toml index a386ec2b43a..01e8b92e149 100644 --- a/library/rustc-std-workspace-core/Cargo.toml +++ b/library/rustc-std-workspace-core/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "rustc-std-workspace-core" version = "1.99.0" -authors = ["Alex Crichton <alex@alexcrichton.com>"] license = 'MIT OR Apache-2.0' description = """ Hack for the compiler's own build system diff --git a/library/rustc-std-workspace-std/Cargo.toml b/library/rustc-std-workspace-std/Cargo.toml index ed6765556cc..811bc78d210 100644 --- a/library/rustc-std-workspace-std/Cargo.toml +++ b/library/rustc-std-workspace-std/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "rustc-std-workspace-std" version = "1.99.0" -authors = ["Alex Crichton <alex@alexcrichton.com>"] license = 'MIT OR Apache-2.0' description = """ Hack for the compiler's own build system diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml index 415d874c7fa..7e260aaa428 100644 --- a/library/std/Cargo.toml +++ b/library/std/Cargo.toml @@ -1,5 +1,4 @@ [package] -authors = ["The Rust Project Developers"] name = "std" version = "0.0.0" license = "MIT OR Apache-2.0" @@ -16,7 +15,7 @@ cfg-if = { version = "0.1.8", features = ['rustc-dep-of-std'] } panic_unwind = { path = "../panic_unwind", optional = true } panic_abort = { path = "../panic_abort" } core = { path = "../core" } -libc = { version = "0.2.93", default-features = false, features = ['rustc-dep-of-std'] } +libc = { version = "0.2.99", default-features = false, features = ['rustc-dep-of-std'] } compiler_builtins = { version = "0.1.44" } profiler_builtins = { path = "../profiler_builtins", optional = true } unwind = { path = "../unwind" } @@ -43,7 +42,7 @@ dlmalloc = { version = "0.2.1", features = ['rustc-dep-of-std'] } fortanix-sgx-abi = { version = "0.3.2", features = ['rustc-dep-of-std'] } [target.'cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_os = "hermit"))'.dependencies] -hermit-abi = { version = "0.1.17", features = ['rustc-dep-of-std'] } +hermit-abi = { version = "0.1.19", features = ['rustc-dep-of-std'] } [target.wasm32-wasi.dependencies] wasi = { version = "0.9.0", features = ['rustc-dep-of-std'], default-features = false } diff --git a/library/std/build.rs b/library/std/build.rs index a14ac63c7a8..726157c1f1a 100644 --- a/library/std/build.rs +++ b/library/std/build.rs @@ -26,6 +26,7 @@ fn main() { || target.contains("vxworks") || target.contains("wasm32") || target.contains("asmjs") + || target.contains("espidf") { // These platforms don't have any special requirements. } else { diff --git a/library/std/src/backtrace.rs b/library/std/src/backtrace.rs index 0aae4674b29..9ace3e1b600 100644 --- a/library/std/src/backtrace.rs +++ b/library/std/src/backtrace.rs @@ -35,13 +35,13 @@ //! `BacktraceStatus` enum as a result of `Backtrace::status`. //! //! Like above with accuracy platform support is done on a best effort basis. -//! Sometimes libraries may not be available at runtime or something may go +//! Sometimes libraries might not be available at runtime or something may go //! wrong which would cause a backtrace to not be captured. Please feel free to //! report issues with platforms where a backtrace cannot be captured though! //! //! ## Environment Variables //! -//! The `Backtrace::capture` function may not actually capture a backtrace by +//! The `Backtrace::capture` function might not actually capture a backtrace by //! default. Its behavior is governed by two environment variables: //! //! * `RUST_LIB_BACKTRACE` - if this is set to `0` then `Backtrace::capture` @@ -61,7 +61,7 @@ //! Note that the `Backtrace::force_capture` function can be used to ignore //! these environment variables. Also note that the state of environment //! variables is cached once the first backtrace is created, so altering -//! `RUST_LIB_BACKTRACE` or `RUST_BACKTRACE` at runtime may not actually change +//! `RUST_LIB_BACKTRACE` or `RUST_BACKTRACE` at runtime might not actually change //! how backtraces are captured. #![unstable(feature = "backtrace", issue = "53487")] @@ -399,12 +399,11 @@ impl fmt::Display for Backtrace { let mut f = backtrace_rs::BacktraceFmt::new(fmt, style, &mut print_path); f.add_context()?; for frame in frames { - let mut f = f.frame(); if frame.symbols.is_empty() { - f.print_raw(frame.frame.ip(), None, None, None)?; + f.frame().print_raw(frame.frame.ip(), None, None, None)?; } else { for symbol in frame.symbols.iter() { - f.print_raw_with_column( + f.frame().print_raw_with_column( frame.frame.ip(), symbol.name.as_ref().map(|b| backtrace_rs::SymbolName::new(b)), symbol.filename.as_ref().map(|b| match b { diff --git a/library/std/src/collections/hash/map.rs b/library/std/src/collections/hash/map.rs index a1f52a9c2e8..7e8da13239c 100644 --- a/library/std/src/collections/hash/map.rs +++ b/library/std/src/collections/hash/map.rs @@ -1,5 +1,3 @@ -// ignore-tidy-filelength - #[cfg(test)] mod tests; @@ -10,6 +8,7 @@ use hashbrown::hash_map as base; use crate::borrow::Borrow; use crate::cell::Cell; use crate::collections::TryReserveError; +use crate::collections::TryReserveErrorKind; use crate::fmt::{self, Debug}; #[allow(deprecated)] use crate::hash::{BuildHasher, Hash, Hasher, SipHasher13}; @@ -124,8 +123,21 @@ use crate::sys; /// } /// ``` /// -/// `HashMap` also implements an [`Entry API`](#method.entry), which allows -/// for more complex methods of getting, setting, updating and removing keys and +/// 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), +/// ]); +/// ``` +/// +/// `HashMap` implements an [`Entry API`](#method.entry), which allows +/// for complex methods of getting, setting, updating and removing keys and /// their values: /// /// ``` @@ -179,27 +191,17 @@ use crate::sys; /// } /// /// // Use a HashMap to store the vikings' health points. -/// let mut vikings = HashMap::new(); -/// -/// vikings.insert(Viking::new("Einar", "Norway"), 25); -/// vikings.insert(Viking::new("Olaf", "Denmark"), 24); -/// vikings.insert(Viking::new("Harald", "Iceland"), 12); +/// 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!("{:?} has {} hp", viking, health); /// } /// ``` -/// -/// A `HashMap` with fixed list of elements can be initialized from an array: -/// -/// ``` -/// use std::collections::HashMap; -/// -/// let timber_resources: HashMap<&str, i32> = [("Norway", 100), ("Denmark", 50), ("Iceland", 10)] -/// .iter().cloned().collect(); -/// // use the values stored in map -/// ``` #[cfg_attr(not(test), rustc_diagnostic_item = "hashmap_type")] #[stable(feature = "rust1", since = "1.0.0")] @@ -454,7 +456,6 @@ impl<K, V, S> HashMap<K, V, S> { /// a.insert(1, "a"); /// assert_eq!(a.len(), 1); /// ``` - #[doc(alias = "length")] #[stable(feature = "rust1", since = "1.0.0")] pub fn len(&self) -> usize { self.base.len() @@ -666,7 +667,6 @@ where /// # Examples /// /// ``` - /// #![feature(shrink_to)] /// use std::collections::HashMap; /// /// let mut map: HashMap<i32, i32> = HashMap::with_capacity(100); @@ -679,7 +679,7 @@ where /// assert!(map.capacity() >= 2); /// ``` #[inline] - #[unstable(feature = "shrink_to", reason = "new API", issue = "56431")] + #[stable(feature = "shrink_to", since = "1.56.0")] pub fn shrink_to(&mut self, min_capacity: usize) { self.base.shrink_to(min_capacity); } @@ -893,7 +893,6 @@ where /// assert_eq!(map.remove(&1), Some("a")); /// assert_eq!(map.remove(&1), None); /// ``` - #[doc(alias = "delete")] #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn remove<Q: ?Sized>(&mut self, k: &Q) -> Option<V> @@ -936,6 +935,7 @@ where /// Retains only the elements specified by the predicate. /// /// In other words, remove all pairs `(k, v)` such that `f(&k, &mut v)` returns `false`. + /// The elements are visited in unsorted (and unspecified) order. /// /// # Examples /// @@ -1149,6 +1149,37 @@ where } } +#[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<K, V, const N: usize> From<[(K, V); N]> for HashMap<K, V, RandomState> +where + K: Eq + Hash, +{ + /// # 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 { + crate::array::IntoIter::new(arr).collect() + } +} + /// An iterator over the entries of a `HashMap`. /// /// This `struct` is created by the [`iter`] method on [`HashMap`]. See its @@ -1831,6 +1862,7 @@ impl<K, V, S> Debug for RawEntryBuilder<'_, K, V, S> { /// /// [`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> { /// An occupied entry. #[stable(feature = "rust1", since = "1.0.0")] @@ -2787,15 +2819,7 @@ where #[inline] fn extend_reserve(&mut self, additional: usize) { - // self.base.extend_reserve(additional); - // FIXME: hashbrown should implement this method. - // But until then, use the same reservation logic: - - // Reserve the entire hint lower bound if the map is empty. - // Otherwise reserve half the hint (rounded up), so the map - // will only resize twice in the worst case. - let reserve = if self.is_empty() { additional } else { (additional + 1) / 2 }; - self.base.reserve(reserve); + self.base.extend_reserve(additional); } } @@ -2966,9 +2990,11 @@ fn map_entry<'a, K: 'a, V: 'a>(raw: base::RustcEntry<'a, K, V>) -> Entry<'a, K, #[inline] pub(super) fn map_try_reserve_error(err: hashbrown::TryReserveError) -> TryReserveError { match err { - hashbrown::TryReserveError::CapacityOverflow => TryReserveError::CapacityOverflow, + hashbrown::TryReserveError::CapacityOverflow => { + TryReserveErrorKind::CapacityOverflow.into() + } hashbrown::TryReserveError::AllocError { layout } => { - TryReserveError::AllocError { layout, non_exhaustive: () } + TryReserveErrorKind::AllocError { layout, non_exhaustive: () }.into() } } } diff --git a/library/std/src/collections/hash/map/tests.rs b/library/std/src/collections/hash/map/tests.rs index 819be142227..d9b20aee2d2 100644 --- a/library/std/src/collections/hash/map/tests.rs +++ b/library/std/src/collections/hash/map/tests.rs @@ -1,9 +1,10 @@ use super::Entry::{Occupied, Vacant}; use super::HashMap; use super::RandomState; +use crate::assert_matches::assert_matches; use crate::cell::RefCell; use rand::{thread_rng, Rng}; -use realstd::collections::TryReserveError::*; +use realstd::collections::TryReserveErrorKind::*; // https://github.com/rust-lang/rust/issues/62301 fn _assert_hashmap_is_unwind_safe() { @@ -821,15 +822,17 @@ fn test_try_reserve() { const MAX_USIZE: usize = usize::MAX; - if let Err(CapacityOverflow) = empty_bytes.try_reserve(MAX_USIZE) { - } else { - panic!("usize::MAX should trigger an overflow!"); - } - - if let Err(AllocError { .. }) = empty_bytes.try_reserve(MAX_USIZE / 8) { - } else { - panic!("usize::MAX / 8 should trigger an OOM!") - } + assert_matches!( + empty_bytes.try_reserve(MAX_USIZE).map_err(|e| e.kind()), + Err(CapacityOverflow), + "usize::MAX should trigger an overflow!" + ); + + assert_matches!( + empty_bytes.try_reserve(MAX_USIZE / 8).map_err(|e| e.kind()), + Err(AllocError { .. }), + "usize::MAX / 8 should trigger an OOM!" + ); } #[test] @@ -1085,3 +1088,15 @@ mod test_drain_filter { assert_eq!(map.len(), 2); } } + +#[test] +fn from_array() { + let map = HashMap::from([(1, 2), (3, 4)]); + let unordered_duplicates = HashMap::from([(3, 4), (1, 2), (1, 2)]); + assert_eq!(map, unordered_duplicates); + + // This next line must infer the hasher type parameter. + // If you make a change that causes this line to no longer infer, + // that's a problem! + let _must_not_require_type_annotation = HashMap::from([(1, 2)]); +} diff --git a/library/std/src/collections/hash/set.rs b/library/std/src/collections/hash/set.rs index 5220c8ad709..3b61acd122e 100644 --- a/library/std/src/collections/hash/set.rs +++ b/library/std/src/collections/hash/set.rs @@ -95,14 +95,12 @@ use super::map::{map_try_reserve_error, RandomState}; /// } /// ``` /// -/// A `HashSet` with fixed list of elements can be initialized from an array: +/// A `HashSet` with a known list of items can be initialized from an array: /// /// ``` /// use std::collections::HashSet; /// -/// let viking_names: HashSet<&'static str> = -/// [ "Einar", "Olaf", "Harald" ].iter().cloned().collect(); -/// // use the values stored in the set +/// let viking_names = HashSet::from(["Einar", "Olaf", "Harald"]); /// ``` /// /// [hash set]: crate::collections#use-the-set-variant-of-any-of-these-maps-when @@ -202,7 +200,6 @@ impl<T, S> HashSet<T, S> { /// v.insert(1); /// assert_eq!(v.len(), 1); /// ``` - #[doc(alias = "length")] #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn len(&self) -> usize { @@ -467,7 +464,6 @@ where /// # Examples /// /// ``` - /// #![feature(shrink_to)] /// use std::collections::HashSet; /// /// let mut set = HashSet::with_capacity(100); @@ -480,7 +476,7 @@ where /// assert!(set.capacity() >= 2); /// ``` #[inline] - #[unstable(feature = "shrink_to", reason = "new API", issue = "56431")] + #[stable(feature = "shrink_to", since = "1.56.0")] pub fn shrink_to(&mut self, min_capacity: usize) { self.base.shrink_to(min_capacity) } @@ -875,7 +871,6 @@ where /// assert_eq!(set.remove(&2), true); /// assert_eq!(set.remove(&2), false); /// ``` - #[doc(alias = "delete")] #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn remove<Q: ?Sized>(&mut self, value: &Q) -> bool @@ -914,6 +909,7 @@ where /// Retains only the elements specified by the predicate. /// /// In other words, remove all elements `e` such that `f(&e)` returns `false`. + /// The elements are visited in unsorted (and unspecified) order. /// /// # Examples /// @@ -998,6 +994,37 @@ where } } +#[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<T, const N: usize> From<[T; N]> for HashSet<T, RandomState> +where + T: Eq + Hash, +{ + /// # 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 { + crate::array::IntoIter::new(arr).collect() + } +} + #[stable(feature = "rust1", since = "1.0.0")] impl<T, S> Extend<T> for HashSet<T, S> where diff --git a/library/std/src/collections/hash/set/tests.rs b/library/std/src/collections/hash/set/tests.rs index 40f8467fd93..6a625e6243c 100644 --- a/library/std/src/collections/hash/set/tests.rs +++ b/library/std/src/collections/hash/set/tests.rs @@ -484,3 +484,15 @@ fn test_drain_filter_pred_panic_leak() { assert_eq!(DROPS.load(Ordering::SeqCst), 3); assert_eq!(set.len(), 0); } + +#[test] +fn from_array() { + let set = HashSet::from([1, 2, 3, 4]); + let unordered_duplicates = HashSet::from([4, 1, 4, 3, 2]); + assert_eq!(set, unordered_duplicates); + + // This next line must infer the hasher type parameter. + // If you make a change that causes this line to no longer infer, + // that's a problem! + let _must_not_require_type_annotation = HashSet::from([1, 2]); +} diff --git a/library/std/src/collections/mod.rs b/library/std/src/collections/mod.rs index 8cda601edd1..130bb5cb2b3 100644 --- a/library/std/src/collections/mod.rs +++ b/library/std/src/collections/mod.rs @@ -422,6 +422,12 @@ pub use self::hash_set::HashSet; #[unstable(feature = "try_reserve", reason = "new API", issue = "48043")] pub use alloc_crate::collections::TryReserveError; +#[unstable( + feature = "try_reserve_kind", + reason = "Uncertain how much info should be exposed", + issue = "48043" +)] +pub use alloc_crate::collections::TryReserveErrorKind; mod hash; diff --git a/library/std/src/env.rs b/library/std/src/env.rs index 4403280efc1..a7465200955 100644 --- a/library/std/src/env.rs +++ b/library/std/src/env.rs @@ -185,15 +185,13 @@ impl fmt::Debug for VarsOs { /// /// # Errors /// -/// Errors if the environment variable is not present. -/// Errors if the environment variable is not valid Unicode. If this is not desired, consider using -/// [`var_os`]. +/// This function will return an error if the environment variable isn't set. /// -/// # Panics +/// This function may return an error if the environment variable's name contains +/// the equal sign character (`=`) or the NUL character. /// -/// This function may panic if `key` is empty, contains an ASCII equals sign -/// `'='` or the NUL character `'\0'`, or when the value contains the NUL -/// character. +/// This function will return an error if the environment variable's value is +/// not valid Unicode. If this is not desired, consider using [`var_os`]. /// /// # Examples /// @@ -219,18 +217,22 @@ fn _var(key: &OsStr) -> Result<String, VarError> { } /// Fetches the environment variable `key` from the current process, returning -/// [`None`] if the variable isn't set. -/// -/// # Panics -/// -/// This function may panic if `key` is empty, contains an ASCII equals sign -/// `'='` or the NUL character `'\0'`, or when the value contains the NUL -/// character. +/// [`None`] if the variable isn't set or there's another error. /// /// Note that the method will not check if the environment variable /// is valid Unicode. If you want to have an error on invalid UTF-8, /// use the [`var`] function instead. /// +/// # Errors +/// +/// This function returns an error if the environment variable isn't set. +/// +/// This function may return an error if the environment variable's name contains +/// the equal sign character (`=`) or the NUL character. +/// +/// This function may return an error if the environment variable's value contains +/// the NUL character. +/// /// # Examples /// /// ``` @@ -249,7 +251,6 @@ pub fn var_os<K: AsRef<OsStr>>(key: K) -> Option<OsString> { fn _var_os(key: &OsStr) -> Option<OsString> { os_imp::getenv(key) - .unwrap_or_else(|e| panic!("failed to get environment variable `{:?}`: {}", key, e)) } /// The error type for operations interacting with environment variables. @@ -294,7 +295,7 @@ impl Error for VarError { } } -/// Sets the environment variable `k` to the value `v` for the currently running +/// Sets the environment variable `key` to the value `value` for the currently running /// process. /// /// Note that while concurrent access to environment variables is safe in Rust, @@ -305,14 +306,13 @@ impl Error for VarError { /// /// Discussion of this unsafety on Unix may be found in: /// -/// - [Austin Group Bugzilla](http://austingroupbugs.net/view.php?id=188) +/// - [Austin Group Bugzilla](https://austingroupbugs.net/view.php?id=188) /// - [GNU C library Bugzilla](https://sourceware.org/bugzilla/show_bug.cgi?id=15607#c2) /// /// # Panics /// -/// This function may panic if `key` is empty, contains an ASCII equals sign -/// `'='` or the NUL character `'\0'`, or when the value contains the NUL -/// character. +/// This function may panic if `key` is empty, contains an ASCII equals sign `'='` +/// or the NUL character `'\0'`, or when `value` contains the NUL character. /// /// # Examples /// @@ -344,7 +344,7 @@ fn _set_var(key: &OsStr, value: &OsStr) { /// /// Discussion of this unsafety on Unix may be found in: /// -/// - [Austin Group Bugzilla](http://austingroupbugs.net/view.php?id=188) +/// - [Austin Group Bugzilla](https://austingroupbugs.net/view.php?id=188) /// - [GNU C library Bugzilla](https://sourceware.org/bugzilla/show_bug.cgi?id=15607#c2) /// /// # Panics @@ -683,7 +683,7 @@ pub fn current_exe() -> io::Result<PathBuf> { /// for more. /// /// The first element is traditionally the path of the executable, but it can be -/// set to arbitrary text, and may not even exist. This means this property +/// set to arbitrary text, and might not even exist. This means this property /// should not be relied upon for security purposes. /// /// [`env::args()`]: args @@ -699,7 +699,7 @@ pub struct Args { /// for more. /// /// The first element is traditionally the path of the executable, but it can be -/// set to arbitrary text, and may not even exist. This means this property +/// set to arbitrary text, and might not even exist. This means this property /// should not be relied upon for security purposes. /// /// [`env::args_os()`]: args_os @@ -712,7 +712,7 @@ pub struct ArgsOs { /// via the command line). /// /// The first element is traditionally the path of the executable, but it can be -/// set to arbitrary text, and may not even exist. This means this property should +/// set to arbitrary text, and might not even exist. This means this property should /// not be relied upon for security purposes. /// /// On Unix systems the shell usually expands unquoted arguments with glob patterns @@ -749,7 +749,7 @@ pub fn args() -> Args { /// via the command line). /// /// The first element is traditionally the path of the executable, but it can be -/// set to arbitrary text, and may not even exist. This means this property should +/// set to arbitrary text, and might not even exist. This means this property should /// not be relied upon for security purposes. /// /// On Unix systems the shell usually expands unquoted arguments with glob patterns diff --git a/library/std/src/error.rs b/library/std/src/error.rs index 14c2f961d32..ec9f0122950 100644 --- a/library/std/src/error.rs +++ b/library/std/src/error.rs @@ -597,6 +597,9 @@ impl Error for char::ParseCharError { #[unstable(feature = "try_reserve", reason = "new API", issue = "48043")] impl Error for alloc::collections::TryReserveError {} +#[unstable(feature = "duration_checked_float", issue = "83400")] +impl Error for core::time::FromSecsError {} + // Copied from `any.rs`. impl dyn Error + 'static { /// Returns `true` if the boxed type is the same as `T` diff --git a/library/std/src/f32.rs b/library/std/src/f32.rs index c16d27fa1f5..0b392897f9d 100644 --- a/library/std/src/f32.rs +++ b/library/std/src/f32.rs @@ -324,18 +324,20 @@ impl f32 { /// Returns the square root of a number. /// - /// Returns NaN if `self` is a negative number. + /// Returns NaN if `self` is a negative number other than `-0.0`. /// /// # Examples /// /// ``` /// let positive = 4.0_f32; /// let negative = -4.0_f32; + /// let negative_zero = -0.0_f32; /// /// let abs_difference = (positive.sqrt() - 2.0).abs(); /// /// assert!(abs_difference <= f32::EPSILON); /// assert!(negative.sqrt().is_nan()); + /// assert!(negative_zero.sqrt() == negative_zero); /// ``` #[must_use = "method returns a new number and does not mutate the original value"] #[stable(feature = "rust1", since = "1.0.0")] @@ -407,7 +409,7 @@ impl f32 { /// Returns the logarithm of the number with respect to an arbitrary base. /// - /// The result may not be correctly rounded owing to implementation details; + /// The result might not be correctly rounded owing to implementation details; /// `self.log2()` can produce more accurate results for base 2, and /// `self.log10()` can produce more accurate results for base 10. /// @@ -876,4 +878,40 @@ impl f32 { pub fn atanh(self) -> f32 { 0.5 * ((2.0 * self) / (1.0 - self)).ln_1p() } + + /// Linear interpolation between `start` and `end`. + /// + /// This enables linear interpolation between `start` and `end`, where start is represented by + /// `self == 0.0` and `end` is represented by `self == 1.0`. This is the basis of all + /// "transition", "easing", or "step" functions; if you change `self` from 0.0 to 1.0 + /// at a given rate, the result will change from `start` to `end` at a similar rate. + /// + /// Values below 0.0 or above 1.0 are allowed, allowing you to extrapolate values outside the + /// range from `start` to `end`. This also is useful for transition functions which might + /// move slightly past the end or start for a desired effect. Mathematically, the values + /// returned are equivalent to `start + self * (end - start)`, although we make a few specific + /// guarantees that are useful specifically to linear interpolation. + /// + /// These guarantees are: + /// + /// * If `start` and `end` are [finite], the value at 0.0 is always `start` and the + /// value at 1.0 is always `end`. (exactness) + /// * If `start` and `end` are [finite], the values will always move in the direction from + /// `start` to `end` (monotonicity) + /// * If `self` is [finite] and `start == end`, the value at any point will always be + /// `start == end`. (consistency) + /// + /// [finite]: #method.is_finite + #[must_use = "method returns a new number and does not mutate the original value"] + #[unstable(feature = "float_interpolation", issue = "86269")] + pub fn lerp(self, start: f32, end: f32) -> f32 { + // consistent + if start == end { + start + + // exact/monotonic + } else { + self.mul_add(end, (-self).mul_add(start, start)) + } + } } diff --git a/library/std/src/f32/tests.rs b/library/std/src/f32/tests.rs index 0d4b865f339..fe66a73afd6 100644 --- a/library/std/src/f32/tests.rs +++ b/library/std/src/f32/tests.rs @@ -757,3 +757,66 @@ fn test_total_cmp() { assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&f32::INFINITY)); assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&s_nan())); } + +#[test] +fn test_lerp_exact() { + // simple values + assert_eq!(f32::lerp(0.0, 2.0, 4.0), 2.0); + assert_eq!(f32::lerp(1.0, 2.0, 4.0), 4.0); + + // boundary values + assert_eq!(f32::lerp(0.0, f32::MIN, f32::MAX), f32::MIN); + assert_eq!(f32::lerp(1.0, f32::MIN, f32::MAX), f32::MAX); +} + +#[test] +fn test_lerp_consistent() { + assert_eq!(f32::lerp(f32::MAX, f32::MIN, f32::MIN), f32::MIN); + assert_eq!(f32::lerp(f32::MIN, f32::MAX, f32::MAX), f32::MAX); + + // as long as t is finite, a/b can be infinite + assert_eq!(f32::lerp(f32::MAX, f32::NEG_INFINITY, f32::NEG_INFINITY), f32::NEG_INFINITY); + assert_eq!(f32::lerp(f32::MIN, f32::INFINITY, f32::INFINITY), f32::INFINITY); +} + +#[test] +fn test_lerp_nan_infinite() { + // non-finite t is not NaN if a/b different + assert!(!f32::lerp(f32::INFINITY, f32::MIN, f32::MAX).is_nan()); + assert!(!f32::lerp(f32::NEG_INFINITY, f32::MIN, f32::MAX).is_nan()); +} + +#[test] +fn test_lerp_values() { + // just a few basic values + assert_eq!(f32::lerp(0.25, 1.0, 2.0), 1.25); + assert_eq!(f32::lerp(0.50, 1.0, 2.0), 1.50); + assert_eq!(f32::lerp(0.75, 1.0, 2.0), 1.75); +} + +#[test] +fn test_lerp_monotonic() { + // near 0 + let below_zero = f32::lerp(-f32::EPSILON, f32::MIN, f32::MAX); + let zero = f32::lerp(0.0, f32::MIN, f32::MAX); + let above_zero = f32::lerp(f32::EPSILON, f32::MIN, f32::MAX); + assert!(below_zero <= zero); + assert!(zero <= above_zero); + assert!(below_zero <= above_zero); + + // near 0.5 + let below_half = f32::lerp(0.5 - f32::EPSILON, f32::MIN, f32::MAX); + let half = f32::lerp(0.5, f32::MIN, f32::MAX); + let above_half = f32::lerp(0.5 + f32::EPSILON, f32::MIN, f32::MAX); + assert!(below_half <= half); + assert!(half <= above_half); + assert!(below_half <= above_half); + + // near 1 + let below_one = f32::lerp(1.0 - f32::EPSILON, f32::MIN, f32::MAX); + let one = f32::lerp(1.0, f32::MIN, f32::MAX); + let above_one = f32::lerp(1.0 + f32::EPSILON, f32::MIN, f32::MAX); + assert!(below_one <= one); + assert!(one <= above_one); + assert!(below_one <= above_one); +} diff --git a/library/std/src/f64.rs b/library/std/src/f64.rs index 4c95df5ffe0..602cceb5d1a 100644 --- a/library/std/src/f64.rs +++ b/library/std/src/f64.rs @@ -324,18 +324,20 @@ impl f64 { /// Returns the square root of a number. /// - /// Returns NaN if `self` is a negative number. + /// Returns NaN if `self` is a negative number other than `-0.0`. /// /// # Examples /// /// ``` /// let positive = 4.0_f64; /// let negative = -4.0_f64; + /// let negative_zero = -0.0_f64; /// /// let abs_difference = (positive.sqrt() - 2.0).abs(); /// /// assert!(abs_difference < 1e-10); /// assert!(negative.sqrt().is_nan()); + /// assert!(negative_zero.sqrt() == negative_zero); /// ``` #[must_use = "method returns a new number and does not mutate the original value"] #[stable(feature = "rust1", since = "1.0.0")] @@ -407,7 +409,7 @@ impl f64 { /// Returns the logarithm of the number with respect to an arbitrary base. /// - /// The result may not be correctly rounded owing to implementation details; + /// The result might not be correctly rounded owing to implementation details; /// `self.log2()` can produce more accurate results for base 2, and /// `self.log10()` can produce more accurate results for base 10. /// @@ -879,6 +881,42 @@ impl f64 { 0.5 * ((2.0 * self) / (1.0 - self)).ln_1p() } + /// Linear interpolation between `start` and `end`. + /// + /// This enables linear interpolation between `start` and `end`, where start is represented by + /// `self == 0.0` and `end` is represented by `self == 1.0`. This is the basis of all + /// "transition", "easing", or "step" functions; if you change `self` from 0.0 to 1.0 + /// at a given rate, the result will change from `start` to `end` at a similar rate. + /// + /// Values below 0.0 or above 1.0 are allowed, allowing you to extrapolate values outside the + /// range from `start` to `end`. This also is useful for transition functions which might + /// move slightly past the end or start for a desired effect. Mathematically, the values + /// returned are equivalent to `start + self * (end - start)`, although we make a few specific + /// guarantees that are useful specifically to linear interpolation. + /// + /// These guarantees are: + /// + /// * If `start` and `end` are [finite], the value at 0.0 is always `start` and the + /// value at 1.0 is always `end`. (exactness) + /// * If `start` and `end` are [finite], the values will always move in the direction from + /// `start` to `end` (monotonicity) + /// * If `self` is [finite] and `start == end`, the value at any point will always be + /// `start == end`. (consistency) + /// + /// [finite]: #method.is_finite + #[must_use = "method returns a new number and does not mutate the original value"] + #[unstable(feature = "float_interpolation", issue = "86269")] + pub fn lerp(self, start: f64, end: f64) -> f64 { + // consistent + if start == end { + start + + // exact/monotonic + } else { + self.mul_add(end, (-self).mul_add(start, start)) + } + } + // Solaris/Illumos requires a wrapper around log, log2, and log10 functions // because of their non-standard behavior (e.g., log(-n) returns -Inf instead // of expected NaN). diff --git a/library/std/src/f64/tests.rs b/library/std/src/f64/tests.rs index 5c163cfe90e..04cb0109261 100644 --- a/library/std/src/f64/tests.rs +++ b/library/std/src/f64/tests.rs @@ -753,3 +753,58 @@ fn test_total_cmp() { assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&f64::INFINITY)); assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&s_nan())); } + +#[test] +fn test_lerp_exact() { + // simple values + assert_eq!(f64::lerp(0.0, 2.0, 4.0), 2.0); + assert_eq!(f64::lerp(1.0, 2.0, 4.0), 4.0); + + // boundary values + assert_eq!(f64::lerp(0.0, f64::MIN, f64::MAX), f64::MIN); + assert_eq!(f64::lerp(1.0, f64::MIN, f64::MAX), f64::MAX); +} + +#[test] +fn test_lerp_consistent() { + assert_eq!(f64::lerp(f64::MAX, f64::MIN, f64::MIN), f64::MIN); + assert_eq!(f64::lerp(f64::MIN, f64::MAX, f64::MAX), f64::MAX); + + // as long as t is finite, a/b can be infinite + assert_eq!(f64::lerp(f64::MAX, f64::NEG_INFINITY, f64::NEG_INFINITY), f64::NEG_INFINITY); + assert_eq!(f64::lerp(f64::MIN, f64::INFINITY, f64::INFINITY), f64::INFINITY); +} + +#[test] +fn test_lerp_nan_infinite() { + // non-finite t is not NaN if a/b different + assert!(!f64::lerp(f64::INFINITY, f64::MIN, f64::MAX).is_nan()); + assert!(!f64::lerp(f64::NEG_INFINITY, f64::MIN, f64::MAX).is_nan()); +} + +#[test] +fn test_lerp_values() { + // just a few basic values + assert_eq!(f64::lerp(0.25, 1.0, 2.0), 1.25); + assert_eq!(f64::lerp(0.50, 1.0, 2.0), 1.50); + assert_eq!(f64::lerp(0.75, 1.0, 2.0), 1.75); +} + +#[test] +fn test_lerp_monotonic() { + // near 0 + let below_zero = f64::lerp(-f64::EPSILON, f64::MIN, f64::MAX); + let zero = f64::lerp(0.0, f64::MIN, f64::MAX); + let above_zero = f64::lerp(f64::EPSILON, f64::MIN, f64::MAX); + assert!(below_zero <= zero); + assert!(zero <= above_zero); + assert!(below_zero <= above_zero); + + // near 1 + let below_one = f64::lerp(1.0 - f64::EPSILON, f64::MIN, f64::MAX); + let one = f64::lerp(1.0, f64::MIN, f64::MAX); + let above_one = f64::lerp(1.0 + f64::EPSILON, f64::MIN, f64::MAX); + assert!(below_one <= one); + assert!(one <= above_one); + assert!(below_one <= above_one); +} diff --git a/library/std/src/ffi/mod.rs b/library/std/src/ffi/mod.rs index 0184495eecf..0b7dc256db8 100644 --- a/library/std/src/ffi/mod.rs +++ b/library/std/src/ffi/mod.rs @@ -124,8 +124,8 @@ //! method is an [`OsString`] which can be round-tripped to a Windows //! string losslessly. //! -//! [Unicode scalar value]: http://www.unicode.org/glossary/#unicode_scalar_value -//! [Unicode code point]: http://www.unicode.org/glossary/#code_point +//! [Unicode scalar value]: https://www.unicode.org/glossary/#unicode_scalar_value +//! [Unicode code point]: https://www.unicode.org/glossary/#code_point //! [`env::set_var()`]: crate::env::set_var //! [`env::var_os()`]: crate::env::var_os //! [unix.OsStringExt]: crate::os::unix::ffi::OsStringExt diff --git a/library/std/src/ffi/os_str.rs b/library/std/src/ffi/os_str.rs index ca391ffb3d5..8f4cd6c691c 100644 --- a/library/std/src/ffi/os_str.rs +++ b/library/std/src/ffi/os_str.rs @@ -271,7 +271,9 @@ impl OsString { /// /// Note that the allocator may give the collection more space than it /// requests. Therefore, capacity can not be relied upon to be precisely - /// minimal. Prefer reserve if future insertions are expected. + /// minimal. Prefer [`reserve`] if future insertions are expected. + /// + /// [`reserve`]: OsString::reserve /// /// # Examples /// @@ -319,7 +321,6 @@ impl OsString { /// # Examples /// /// ``` - /// #![feature(shrink_to)] /// use std::ffi::OsString; /// /// let mut s = OsString::from("foo"); @@ -333,7 +334,7 @@ impl OsString { /// assert!(s.capacity() >= 3); /// ``` #[inline] - #[unstable(feature = "shrink_to", reason = "new API", issue = "56431")] + #[stable(feature = "shrink_to", since = "1.56.0")] pub fn shrink_to(&mut self, min_capacity: usize) { self.inner.shrink_to(min_capacity) } @@ -694,7 +695,6 @@ impl OsStr { /// let os_str = OsStr::new("foo"); /// assert_eq!(os_str.len(), 3); /// ``` - #[doc(alias = "length")] #[stable(feature = "osstring_simple_functions", since = "1.9.0")] #[inline] pub fn len(&self) -> usize { diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs index a1636e2f604..2c04481c04e 100644 --- a/library/std/src/fs.rs +++ b/library/std/src/fs.rs @@ -88,6 +88,7 @@ use crate::time::SystemTime; /// [`BufReader<R>`]: io::BufReader /// [`sync_all`]: File::sync_all #[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr(not(test), rustc_diagnostic_item = "File")] pub struct File { inner: fs_imp::File, } @@ -183,12 +184,14 @@ pub struct Permissions(fs_imp::FilePermissions); /// It is returned by [`Metadata::file_type`] method. #[stable(feature = "file_type", since = "1.1.0")] #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] +#[cfg_attr(not(test), rustc_diagnostic_item = "FileType")] pub struct FileType(fs_imp::FileType); /// A builder used to create directories in various manners. /// /// This builder also supports platform-specific options. #[stable(feature = "dir_builder", since = "1.6.0")] +#[cfg_attr(not(test), rustc_diagnostic_item = "DirBuilder")] #[derive(Debug)] pub struct DirBuilder { inner: fs_imp::DirBuilder, @@ -416,7 +419,7 @@ impl File { self.inner.fsync() } - /// This function is similar to [`sync_all`], except that it may not + /// This function is similar to [`sync_all`], except that it might not /// synchronize file metadata to the filesystem. /// /// This is intended for use cases that must synchronize content, but don't @@ -880,8 +883,7 @@ impl OpenOptions { /// This function will return an error under a number of different /// circumstances. Some of these error conditions are listed here, together /// with their [`io::ErrorKind`]. The mapping to [`io::ErrorKind`]s is not - /// part of the compatibility contract of the function, especially the - /// [`Other`] kind might change to more specific kinds in the future. + /// part of the compatibility contract of the function. /// /// * [`NotFound`]: The specified file does not exist and neither `create` /// or `create_new` is set. @@ -895,9 +897,11 @@ impl OpenOptions { /// exists. /// * [`InvalidInput`]: Invalid combinations of open options (truncate /// without write access, no access mode set, etc.). - /// * [`Other`]: One of the directory components of the specified file path + /// + /// The following errors don't match any existing [`io::ErrorKind`] at the moment: + /// * One of the directory components of the specified file path /// was not, in fact, a directory. - /// * [`Other`]: Filesystem-level errors: full disk, write permission + /// * Filesystem-level errors: full disk, write permission /// requested on a read-only file system, exceeded disk quota, too many /// open files, too long filename, too many symbolic links in the /// specified path (Unix-like systems only), etc. @@ -913,7 +917,6 @@ impl OpenOptions { /// [`AlreadyExists`]: io::ErrorKind::AlreadyExists /// [`InvalidInput`]: io::ErrorKind::InvalidInput /// [`NotFound`]: io::ErrorKind::NotFound - /// [`Other`]: io::ErrorKind::Other /// [`PermissionDenied`]: io::ErrorKind::PermissionDenied #[stable(feature = "rust1", since = "1.0.0")] pub fn open<P: AsRef<Path>>(&self, path: P) -> io::Result<File> { @@ -1007,6 +1010,32 @@ impl Metadata { self.file_type().is_file() } + /// Returns `true` if this metadata is for a symbolic link. + /// + /// # Examples + /// + #[cfg_attr(unix, doc = "```no_run")] + #[cfg_attr(not(unix), doc = "```ignore")] + /// #![feature(is_symlink)] + /// use std::fs; + /// use std::path::Path; + /// use std::os::unix::fs::symlink; + /// + /// fn main() -> std::io::Result<()> { + /// let link_path = Path::new("link"); + /// symlink("/origin_does_not_exists/", link_path)?; + /// + /// let metadata = fs::symlink_metadata(link_path)?; + /// + /// assert!(metadata.is_symlink()); + /// Ok(()) + /// } + /// ``` + #[unstable(feature = "is_symlink", issue = "85748")] + pub fn is_symlink(&self) -> bool { + self.file_type().is_symlink() + } + /// Returns the size of the file, in bytes, this metadata is for. /// /// # Examples @@ -1052,7 +1081,7 @@ impl Metadata { /// /// # Errors /// - /// This field may not be available on all platforms, and will return an + /// This field might not be available on all platforms, and will return an /// `Err` on platforms where it is not available. /// /// # Examples @@ -1087,7 +1116,7 @@ impl Metadata { /// /// # Errors /// - /// This field may not be available on all platforms, and will return an + /// This field might not be available on all platforms, and will return an /// `Err` on platforms where it is not available. /// /// # Examples @@ -1119,7 +1148,7 @@ impl Metadata { /// /// # Errors /// - /// This field may not be available on all platforms, and will return an + /// This field might not be available on all platforms, and will return an /// `Err` on platforms or filesystems where it is not available. /// /// # Examples @@ -1525,7 +1554,6 @@ impl AsInner<fs_imp::DirEntry> for DirEntry { /// Ok(()) /// } /// ``` -#[doc(alias = "delete")] #[stable(feature = "rust1", since = "1.0.0")] pub fn remove_file<P: AsRef<Path>>(path: P) -> io::Result<()> { fs_imp::unlink(path.as_ref()) @@ -1711,8 +1739,11 @@ pub fn copy<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> io::Result<u64> { /// /// # Platform-specific behavior /// -/// This function currently corresponds to the `linkat` function with no flags -/// on Unix and the `CreateHardLink` function on Windows. +/// This function currently corresponds the `CreateHardLink` function on Windows. +/// On most Unix systems, it corresponds to the `linkat` function with no flags. +/// On Android, VxWorks, and Redox, it instead corresponds to the `link` function. +/// On MacOS, it uses the `linkat` function if it is available, but on very old +/// systems where `linkat` is not available, `link` is selected at runtime instead. /// Note that, this [may change in the future][changes]. /// /// [changes]: io#platform-specific-behavior @@ -1881,6 +1912,7 @@ pub fn canonicalize<P: AsRef<Path>>(path: P) -> io::Result<PathBuf> { /// Ok(()) /// } /// ``` +#[doc(alias = "mkdir")] #[stable(feature = "rust1", since = "1.0.0")] pub fn create_dir<P: AsRef<Path>>(path: P) -> io::Result<()> { DirBuilder::new().create(path.as_ref()) @@ -1960,7 +1992,7 @@ pub fn create_dir_all<P: AsRef<Path>>(path: P) -> io::Result<()> { /// Ok(()) /// } /// ``` -#[doc(alias = "delete")] +#[doc(alias = "rmdir")] #[stable(feature = "rust1", since = "1.0.0")] pub fn remove_dir<P: AsRef<Path>>(path: P) -> io::Result<()> { fs_imp::rmdir(path.as_ref()) @@ -1998,7 +2030,6 @@ pub fn remove_dir<P: AsRef<Path>>(path: P) -> io::Result<()> { /// Ok(()) /// } /// ``` -#[doc(alias = "delete")] #[stable(feature = "rust1", since = "1.0.0")] pub fn remove_dir_all<P: AsRef<Path>>(path: P) -> io::Result<()> { fs_imp::remove_dir_all(path.as_ref()) @@ -2008,6 +2039,8 @@ pub fn remove_dir_all<P: AsRef<Path>>(path: P) -> io::Result<()> { /// /// The iterator will yield instances of [`io::Result`]`<`[`DirEntry`]`>`. /// New errors may be encountered after an iterator is initially constructed. +/// Entries for the current and parent directories (typically `.` and `..`) are +/// skipped. /// /// # Platform-specific behavior /// @@ -2190,7 +2223,7 @@ impl DirBuilder { Some(p) => self.create_dir_all(p)?, None => { return Err(io::Error::new_const( - io::ErrorKind::Other, + io::ErrorKind::Uncategorized, &"failed to create whole tree", )); } diff --git a/library/std/src/fs/tests.rs b/library/std/src/fs/tests.rs index ce8d3a56f7a..13dbae3b7b5 100644 --- a/library/std/src/fs/tests.rs +++ b/library/std/src/fs/tests.rs @@ -19,6 +19,10 @@ use crate::os::unix::fs::symlink as symlink_junction; use crate::os::windows::fs::{symlink_dir, symlink_file}; #[cfg(windows)] use crate::sys::fs::symlink_junction; +#[cfg(target_os = "macos")] +use crate::sys::weak::weak; +#[cfg(target_os = "macos")] +use libc::{c_char, c_int}; macro_rules! check { ($e:expr) => { @@ -79,6 +83,17 @@ pub fn got_symlink_permission(tmpdir: &TempDir) -> bool { } } +#[cfg(target_os = "macos")] +fn able_to_not_follow_symlinks_while_hard_linking() -> bool { + weak!(fn linkat(c_int, *const c_char, c_int, *const c_char, c_int) -> c_int); + linkat.get().is_some() +} + +#[cfg(not(target_os = "macos"))] +fn able_to_not_follow_symlinks_while_hard_linking() -> bool { + return true; +} + #[test] fn file_test_io_smoke_test() { let message = "it's alright. have a good time"; @@ -809,7 +824,7 @@ fn symlink_noexist() { }; // Use a relative path for testing. Symlinks get normalized by Windows, - // so we may not get the same path back for absolute paths + // so we might not get the same path back for absolute paths check!(symlink_file(&"foo", &tmpdir.join("bar"))); assert_eq!(check!(fs::read_link(&tmpdir.join("bar"))).to_str().unwrap(), "foo"); } @@ -1329,7 +1344,8 @@ fn metadata_access_times() { match (a.created(), b.created()) { (Ok(t1), Ok(t2)) => assert!(t1 <= t2), (Err(e1), Err(e2)) - if e1.kind() == ErrorKind::Other && e2.kind() == ErrorKind::Other + if e1.kind() == ErrorKind::Uncategorized + && e2.kind() == ErrorKind::Uncategorized || e1.kind() == ErrorKind::Unsupported && e2.kind() == ErrorKind::Unsupported => {} (a, b) => { @@ -1346,6 +1362,9 @@ fn symlink_hard_link() { if !got_symlink_permission(&tmpdir) { return; }; + if !able_to_not_follow_symlinks_while_hard_linking() { + return; + } // Create "file", a file. check!(fs::File::create(tmpdir.join("file"))); diff --git a/library/std/src/io/buffered/bufreader.rs b/library/std/src/io/buffered/bufreader.rs index d8021d3e99a..32d194d9616 100644 --- a/library/std/src/io/buffered/bufreader.rs +++ b/library/std/src/io/buffered/bufreader.rs @@ -438,7 +438,13 @@ impl<R: Seek> Seek for BufReader<R> { } impl<T> SizeHint for BufReader<T> { + #[inline] fn lower_bound(&self) -> usize { - self.buffer().len() + SizeHint::lower_bound(self.get_ref()) + self.buffer().len() + } + + #[inline] + fn upper_bound(&self) -> Option<usize> { + SizeHint::upper_bound(self.get_ref()).and_then(|up| self.buffer().len().checked_add(up)) } } diff --git a/library/std/src/io/buffered/bufwriter.rs b/library/std/src/io/buffered/bufwriter.rs index ef2769d431f..9da5fbff9cf 100644 --- a/library/std/src/io/buffered/bufwriter.rs +++ b/library/std/src/io/buffered/bufwriter.rs @@ -68,7 +68,7 @@ use crate::ptr; /// [`flush`]: BufWriter::flush #[stable(feature = "rust1", since = "1.0.0")] pub struct BufWriter<W: Write> { - inner: Option<W>, + inner: W, // The buffer. Avoid using this like a normal `Vec` in common code paths. // That is, don't use `buf.push`, `buf.extend_from_slice`, or any other // methods that require bounds checking or the like. This makes an enormous @@ -112,7 +112,7 @@ impl<W: Write> BufWriter<W> { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn with_capacity(capacity: usize, inner: W) -> BufWriter<W> { - BufWriter { inner: Some(inner), buf: Vec::with_capacity(capacity), panicked: false } + BufWriter { inner, buf: Vec::with_capacity(capacity), panicked: false } } /// Send data in our local buffer into the inner writer, looping as @@ -161,10 +161,9 @@ impl<W: Write> BufWriter<W> { } let mut guard = BufGuard::new(&mut self.buf); - let inner = self.inner.as_mut().unwrap(); while !guard.done() { self.panicked = true; - let r = inner.write(guard.remaining()); + let r = self.inner.write(guard.remaining()); self.panicked = false; match r { @@ -212,7 +211,7 @@ impl<W: Write> BufWriter<W> { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn get_ref(&self) -> &W { - self.inner.as_ref().unwrap() + &self.inner } /// Gets a mutable reference to the underlying writer. @@ -232,7 +231,7 @@ impl<W: Write> BufWriter<W> { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn get_mut(&mut self) -> &mut W { - self.inner.as_mut().unwrap() + &mut self.inner } /// Returns a reference to the internally buffered data. @@ -308,7 +307,7 @@ impl<W: Write> BufWriter<W> { pub fn into_inner(mut self) -> Result<W, IntoInnerError<BufWriter<W>>> { match self.flush_buf() { Err(e) => Err(IntoInnerError::new(self, e)), - Ok(()) => Ok(self.inner.take().unwrap()), + Ok(()) => Ok(self.into_parts().0), } } @@ -319,27 +318,32 @@ impl<W: Write> BufWriter<W> { /// In this case, we return `WriterPanicked` for the buffered data (from which the buffer /// contents can still be recovered). /// - /// `into_raw_parts` makes no attempt to flush data and cannot fail. + /// `into_parts` makes no attempt to flush data and cannot fail. /// /// # Examples /// /// ``` - /// #![feature(bufwriter_into_raw_parts)] + /// #![feature(bufwriter_into_parts)] /// use std::io::{BufWriter, Write}; /// /// let mut buffer = [0u8; 10]; /// let mut stream = BufWriter::new(buffer.as_mut()); /// write!(stream, "too much data").unwrap(); /// stream.flush().expect_err("it doesn't fit"); - /// let (recovered_writer, buffered_data) = stream.into_raw_parts(); + /// let (recovered_writer, buffered_data) = stream.into_parts(); /// assert_eq!(recovered_writer.len(), 0); /// assert_eq!(&buffered_data.unwrap(), b"ata"); /// ``` - #[unstable(feature = "bufwriter_into_raw_parts", issue = "80690")] - pub fn into_raw_parts(mut self) -> (W, Result<Vec<u8>, WriterPanicked>) { + #[unstable(feature = "bufwriter_into_parts", issue = "80690")] + pub fn into_parts(mut self) -> (W, Result<Vec<u8>, WriterPanicked>) { let buf = mem::take(&mut self.buf); let buf = if !self.panicked { Ok(buf) } else { Err(WriterPanicked { buf }) }; - (self.inner.take().unwrap(), buf) + + // SAFETY: forget(self) prevents double dropping inner + let inner = unsafe { ptr::read(&mut self.inner) }; + mem::forget(self); + + (inner, buf) } // Ensure this function does not get inlined into `write`, so that it @@ -440,14 +444,14 @@ impl<W: Write> BufWriter<W> { } } -#[unstable(feature = "bufwriter_into_raw_parts", issue = "80690")] -/// Error returned for the buffered data from `BufWriter::into_raw_parts`, when the underlying +#[unstable(feature = "bufwriter_into_parts", issue = "80690")] +/// Error returned for the buffered data from `BufWriter::into_parts`, when the underlying /// writer has previously panicked. Contains the (possibly partly written) buffered data. /// /// # Example /// /// ``` -/// #![feature(bufwriter_into_raw_parts)] +/// #![feature(bufwriter_into_parts)] /// use std::io::{self, BufWriter, Write}; /// use std::panic::{catch_unwind, AssertUnwindSafe}; /// @@ -463,7 +467,7 @@ impl<W: Write> BufWriter<W> { /// stream.flush().unwrap() /// })); /// assert!(result.is_err()); -/// let (recovered_writer, buffered_data) = stream.into_raw_parts(); +/// let (recovered_writer, buffered_data) = stream.into_parts(); /// assert!(matches!(recovered_writer, PanickingWriter)); /// assert_eq!(buffered_data.unwrap_err().into_inner(), b"some data"); /// ``` @@ -474,7 +478,7 @@ pub struct WriterPanicked { impl WriterPanicked { /// Returns the perhaps-unwritten data. Some of this data may have been written by the /// panicking call(s) to the underlying writer, so simply writing it again is not a good idea. - #[unstable(feature = "bufwriter_into_raw_parts", issue = "80690")] + #[unstable(feature = "bufwriter_into_parts", issue = "80690")] pub fn into_inner(self) -> Vec<u8> { self.buf } @@ -483,7 +487,7 @@ impl WriterPanicked { "BufWriter inner writer panicked, what data remains unwritten is not known"; } -#[unstable(feature = "bufwriter_into_raw_parts", issue = "80690")] +#[unstable(feature = "bufwriter_into_parts", issue = "80690")] impl error::Error for WriterPanicked { #[allow(deprecated, deprecated_in_future)] fn description(&self) -> &str { @@ -491,14 +495,14 @@ impl error::Error for WriterPanicked { } } -#[unstable(feature = "bufwriter_into_raw_parts", issue = "80690")] +#[unstable(feature = "bufwriter_into_parts", issue = "80690")] impl fmt::Display for WriterPanicked { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{}", Self::DESCRIPTION) } } -#[unstable(feature = "bufwriter_into_raw_parts", issue = "80690")] +#[unstable(feature = "bufwriter_into_parts", issue = "80690")] impl fmt::Debug for WriterPanicked { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("WriterPanicked") @@ -643,7 +647,7 @@ where { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct("BufWriter") - .field("writer", &self.inner.as_ref().unwrap()) + .field("writer", &self.inner) .field("buffer", &format_args!("{}/{}", self.buf.len(), self.buf.capacity())) .finish() } @@ -663,7 +667,7 @@ impl<W: Write + Seek> Seek for BufWriter<W> { #[stable(feature = "rust1", since = "1.0.0")] impl<W: Write> Drop for BufWriter<W> { fn drop(&mut self) { - if self.inner.is_some() && !self.panicked { + if !self.panicked { // dtors should not panic, so we ignore a failed flush let _r = self.flush_buf(); } diff --git a/library/std/src/io/buffered/mod.rs b/library/std/src/io/buffered/mod.rs index 65497817f81..8cfffc2fd35 100644 --- a/library/std/src/io/buffered/mod.rs +++ b/library/std/src/io/buffered/mod.rs @@ -14,6 +14,8 @@ use crate::io::Error; pub use bufreader::BufReader; pub use bufwriter::BufWriter; +#[unstable(feature = "bufwriter_into_parts", issue = "80690")] +pub use bufwriter::WriterPanicked; pub use linewriter::LineWriter; use linewritershim::LineWriterShim; @@ -133,7 +135,6 @@ impl<W> IntoInnerError<W> { /// /// # Example /// ``` - /// #![feature(io_into_inner_error_parts)] /// use std::io::{BufWriter, ErrorKind, Write}; /// /// let mut not_enough_space = [0u8; 10]; @@ -143,7 +144,7 @@ impl<W> IntoInnerError<W> { /// let err = into_inner_err.into_error(); /// assert_eq!(err.kind(), ErrorKind::WriteZero); /// ``` - #[unstable(feature = "io_into_inner_error_parts", issue = "79704")] + #[stable(feature = "io_into_inner_error_parts", since = "1.55.0")] pub fn into_error(self) -> Error { self.1 } @@ -156,7 +157,6 @@ impl<W> IntoInnerError<W> { /// /// # Example /// ``` - /// #![feature(io_into_inner_error_parts)] /// use std::io::{BufWriter, ErrorKind, Write}; /// /// let mut not_enough_space = [0u8; 10]; @@ -167,7 +167,7 @@ impl<W> IntoInnerError<W> { /// assert_eq!(err.kind(), ErrorKind::WriteZero); /// assert_eq!(recovered_writer.buffer(), b"t be actually written"); /// ``` - #[unstable(feature = "io_into_inner_error_parts", issue = "79704")] + #[stable(feature = "io_into_inner_error_parts", since = "1.55.0")] pub fn into_parts(self) -> (Error, W) { (self.1, self.0) } diff --git a/library/std/src/io/cursor.rs b/library/std/src/io/cursor.rs index 9527254c947..ae0cea985d7 100644 --- a/library/std/src/io/cursor.rs +++ b/library/std/src/io/cursor.rs @@ -205,6 +205,62 @@ impl<T> Cursor<T> { } } +impl<T> Cursor<T> +where + T: AsRef<[u8]>, +{ + /// Returns the remaining slice. + /// + /// # Examples + /// + /// ``` + /// #![feature(cursor_remaining)] + /// use std::io::Cursor; + /// + /// let mut buff = Cursor::new(vec![1, 2, 3, 4, 5]); + /// + /// assert_eq!(buff.remaining_slice(), &[1, 2, 3, 4, 5]); + /// + /// buff.set_position(2); + /// assert_eq!(buff.remaining_slice(), &[3, 4, 5]); + /// + /// buff.set_position(4); + /// assert_eq!(buff.remaining_slice(), &[5]); + /// + /// buff.set_position(6); + /// assert_eq!(buff.remaining_slice(), &[]); + /// ``` + #[unstable(feature = "cursor_remaining", issue = "86369")] + pub fn remaining_slice(&self) -> &[u8] { + let len = self.pos.min(self.inner.as_ref().len() as u64); + &self.inner.as_ref()[(len as usize)..] + } + + /// Returns `true` if the remaining slice is empty. + /// + /// # Examples + /// + /// ``` + /// #![feature(cursor_remaining)] + /// use std::io::Cursor; + /// + /// let mut buff = Cursor::new(vec![1, 2, 3, 4, 5]); + /// + /// buff.set_position(2); + /// assert!(!buff.is_empty()); + /// + /// buff.set_position(5); + /// assert!(buff.is_empty()); + /// + /// buff.set_position(10); + /// assert!(buff.is_empty()); + /// ``` + #[unstable(feature = "cursor_remaining", issue = "86369")] + pub fn is_empty(&self) -> bool { + self.pos >= self.inner.as_ref().len() as u64 + } +} + #[stable(feature = "rust1", since = "1.0.0")] impl<T> Clone for Cursor<T> where @@ -268,7 +324,7 @@ where T: AsRef<[u8]>, { fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { - let n = Read::read(&mut self.fill_buf()?, buf)?; + let n = Read::read(&mut self.remaining_slice(), buf)?; self.pos += n as u64; Ok(n) } @@ -291,7 +347,7 @@ where fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> { let n = buf.len(); - Read::read_exact(&mut self.fill_buf()?, buf)?; + Read::read_exact(&mut self.remaining_slice(), buf)?; self.pos += n as u64; Ok(()) } @@ -308,8 +364,7 @@ where T: AsRef<[u8]>, { fn fill_buf(&mut self) -> io::Result<&[u8]> { - let amt = cmp::min(self.pos, self.inner.as_ref().len() as u64); - Ok(&self.inner.as_ref()[(amt as usize)..]) + Ok(self.remaining_slice()) } fn consume(&mut self, amt: usize) { self.pos += amt as u64; diff --git a/library/std/src/io/error.rs b/library/std/src/io/error.rs index 56e6f08268c..829ef3d98bb 100644 --- a/library/std/src/io/error.rs +++ b/library/std/src/io/error.rs @@ -105,6 +105,12 @@ pub enum ErrorKind { /// The connection was reset by the remote server. #[stable(feature = "rust1", since = "1.0.0")] ConnectionReset, + /// The remote host is not reachable. + #[unstable(feature = "io_error_more", issue = "86442")] + HostUnreachable, + /// The network containing the remote host is not reachable. + #[unstable(feature = "io_error_more", issue = "86442")] + NetworkUnreachable, /// The connection was aborted (terminated) by the remote server. #[stable(feature = "rust1", since = "1.0.0")] ConnectionAborted, @@ -119,6 +125,9 @@ pub enum ErrorKind { /// local. #[stable(feature = "rust1", since = "1.0.0")] AddrNotAvailable, + /// The system's networking is down. + #[unstable(feature = "io_error_more", issue = "86442")] + NetworkDown, /// The operation failed because a pipe was closed. #[stable(feature = "rust1", since = "1.0.0")] BrokenPipe, @@ -129,6 +138,38 @@ pub enum ErrorKind { /// requested to not occur. #[stable(feature = "rust1", since = "1.0.0")] WouldBlock, + /// A filesystem object is, unexpectedly, not a directory. + /// + /// For example, a filesystem path was specified where one of the intermediate directory + /// components was, in fact, a plain file. + #[unstable(feature = "io_error_more", issue = "86442")] + NotADirectory, + /// The filesystem object is, unexpectedly, a directory. + /// + /// A directory was specified when a non-directory was expected. + #[unstable(feature = "io_error_more", issue = "86442")] + IsADirectory, + /// A non-empty directory was specified where an empty directory was expected. + #[unstable(feature = "io_error_more", issue = "86442")] + DirectoryNotEmpty, + /// The filesystem or storage medium is read-only, but a write operation was attempted. + #[unstable(feature = "io_error_more", issue = "86442")] + ReadOnlyFilesystem, + /// Loop in the filesystem or IO subsystem; often, too many levels of symbolic links. + /// + /// There was a loop (or excessively long chain) resolving a filesystem object + /// or file IO object. + /// + /// On Unix this is usually the result of a symbolic link loop; or, of exceeding the + /// system-specific limit on the depth of symlink traversal. + #[unstable(feature = "io_error_more", issue = "86442")] + FilesystemLoop, + /// Stale network file handle. + /// + /// With some network filesystems, notably NFS, an open file (or directory) can be invalidated + /// by problems with the network or server. + #[unstable(feature = "io_error_more", issue = "86442")] + StaleNetworkFileHandle, /// A parameter was incorrect. #[stable(feature = "rust1", since = "1.0.0")] InvalidInput, @@ -158,17 +199,78 @@ pub enum ErrorKind { /// [`Ok(0)`]: Ok #[stable(feature = "rust1", since = "1.0.0")] WriteZero, + /// The underlying storage (typically, a filesystem) is full. + /// + /// This does not include out of quota errors. + #[unstable(feature = "io_error_more", issue = "86442")] + StorageFull, + /// Seek on unseekable file. + /// + /// Seeking was attempted on an open file handle which is not suitable for seeking - for + /// example, on Unix, a named pipe opened with `File::open`. + #[unstable(feature = "io_error_more", issue = "86442")] + NotSeekable, + /// Filesystem quota was exceeded. + #[unstable(feature = "io_error_more", issue = "86442")] + FilesystemQuotaExceeded, + /// File larger than allowed or supported. + /// + /// This might arise from a hard limit of the underlying filesystem or file access API, or from + /// an administratively imposed resource limitation. Simple disk full, and out of quota, have + /// their own errors. + #[unstable(feature = "io_error_more", issue = "86442")] + FileTooLarge, + /// Resource is busy. + #[unstable(feature = "io_error_more", issue = "86442")] + ResourceBusy, + /// Executable file is busy. + /// + /// An attempt was made to write to a file which is also in use as a running program. (Not all + /// operating systems detect this situation.) + #[unstable(feature = "io_error_more", issue = "86442")] + ExecutableFileBusy, + /// Deadlock (avoided). + /// + /// A file locking operation would result in deadlock. This situation is typically detected, if + /// at all, on a best-effort basis. + #[unstable(feature = "io_error_more", issue = "86442")] + Deadlock, + /// Cross-device or cross-filesystem (hard) link or rename. + #[unstable(feature = "io_error_more", issue = "86442")] + CrossesDevices, + /// Too many (hard) links to the same filesystem object. + /// + /// The filesystem does not support making so many hardlinks to the same file. + #[unstable(feature = "io_error_more", issue = "86442")] + TooManyLinks, + /// Filename too long. + /// + /// The limit might be from the underlying filesystem or API, or an administratively imposed + /// resource limit. + #[unstable(feature = "io_error_more", issue = "86442")] + FilenameTooLong, + /// Program argument list too long. + /// + /// When trying to run an external program, a system or process limit on the size of the + /// arguments would have been exceeded. + #[unstable(feature = "io_error_more", issue = "86442")] + ArgumentListTooLong, /// This operation was interrupted. /// /// Interrupted operations can typically be retried. #[stable(feature = "rust1", since = "1.0.0")] Interrupted, - /// Any I/O error not part of this list. + + /// A custom error that does not fall under any other I/O error kind. /// - /// Errors that are `Other` now may move to a different or a new - /// [`ErrorKind`] variant in the future. It is not recommended to match - /// an error against `Other` and to expect any additional characteristics, - /// e.g., a specific [`Error::raw_os_error`] return value. + /// This can be used to construct your own [`Error`]s that do not match any + /// [`ErrorKind`]. + /// + /// This [`ErrorKind`] is not used by the standard library. + /// + /// Errors from the standard library that do not fall under any of the I/O + /// error kinds cannot be `match`ed on, and will only match a wildcard (`_`) pattern. + /// New [`ErrorKind`]s might be added in the future for some of those. #[stable(feature = "rust1", since = "1.0.0")] Other, @@ -191,31 +293,62 @@ pub enum ErrorKind { /// to allocate enough memory. #[stable(feature = "out_of_memory_error", since = "1.54.0")] OutOfMemory, + + /// Any I/O error from the standard library that's not part of this list. + /// + /// Errors that are `Uncategorized` now may move to a different or a new + /// [`ErrorKind`] variant in the future. It is not recommended to match + /// an error against `Uncategorized`; use a wildcard match (`_`) instead. + #[unstable(feature = "io_error_uncategorized", issue = "none")] + #[doc(hidden)] + Uncategorized, } impl ErrorKind { pub(crate) fn as_str(&self) -> &'static str { + use ErrorKind::*; match *self { - ErrorKind::NotFound => "entity not found", - ErrorKind::PermissionDenied => "permission denied", - ErrorKind::ConnectionRefused => "connection refused", - ErrorKind::ConnectionReset => "connection reset", - ErrorKind::ConnectionAborted => "connection aborted", - ErrorKind::NotConnected => "not connected", - ErrorKind::AddrInUse => "address in use", - ErrorKind::AddrNotAvailable => "address not available", - ErrorKind::BrokenPipe => "broken pipe", - ErrorKind::AlreadyExists => "entity already exists", - ErrorKind::WouldBlock => "operation would block", - ErrorKind::InvalidInput => "invalid input parameter", - ErrorKind::InvalidData => "invalid data", - ErrorKind::TimedOut => "timed out", - ErrorKind::WriteZero => "write zero", - ErrorKind::Interrupted => "operation interrupted", - ErrorKind::Other => "other os error", - ErrorKind::UnexpectedEof => "unexpected end of file", - ErrorKind::Unsupported => "unsupported", - ErrorKind::OutOfMemory => "out of memory", + AddrInUse => "address in use", + AddrNotAvailable => "address not available", + AlreadyExists => "entity already exists", + ArgumentListTooLong => "argument list too long", + BrokenPipe => "broken pipe", + ResourceBusy => "resource busy", + ConnectionAborted => "connection aborted", + ConnectionRefused => "connection refused", + ConnectionReset => "connection reset", + CrossesDevices => "cross-device link or rename", + Deadlock => "deadlock", + DirectoryNotEmpty => "directory not empty", + ExecutableFileBusy => "executable file busy", + FilenameTooLong => "filename too long", + FilesystemQuotaExceeded => "filesystem quota exceeded", + FileTooLarge => "file too large", + HostUnreachable => "host unreachable", + Interrupted => "operation interrupted", + InvalidData => "invalid data", + InvalidInput => "invalid input parameter", + IsADirectory => "is a directory", + NetworkDown => "network down", + NetworkUnreachable => "network unreachable", + NotADirectory => "not a directory", + StorageFull => "no storage space", + NotConnected => "not connected", + NotFound => "entity not found", + Other => "other error", + OutOfMemory => "out of memory", + PermissionDenied => "permission denied", + ReadOnlyFilesystem => "read-only filesystem or storage medium", + StaleNetworkFileHandle => "stale network file handle", + FilesystemLoop => "filesystem loop or indirection limit (e.g. symlink loop)", + NotSeekable => "seek on unseekable file", + TimedOut => "timed out", + TooManyLinks => "too many links", + Uncategorized => "uncategorized error", + UnexpectedEof => "unexpected end of file", + Unsupported => "unsupported", + WouldBlock => "operation would block", + WriteZero => "write zero", } } } @@ -538,7 +671,7 @@ impl Error { /// } /// /// fn main() { - /// // Will print "Other". + /// // Will print "Uncategorized". /// print_error(Error::last_os_error()); /// // Will print "AddrInUse". /// print_error(Error::new(ErrorKind::AddrInUse, "oh no!")); diff --git a/library/std/src/io/impls.rs b/library/std/src/io/impls.rs index 6891bd8a664..7a2a49ba7d7 100644 --- a/library/std/src/io/impls.rs +++ b/library/std/src/io/impls.rs @@ -87,6 +87,11 @@ impl<S: Seek + ?Sized> Seek for &mut S { fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> { (**self).seek(pos) } + + #[inline] + fn stream_position(&mut self) -> io::Result<u64> { + (**self).stream_position() + } } #[stable(feature = "rust1", since = "1.0.0")] impl<B: BufRead + ?Sized> BufRead for &mut B { @@ -186,6 +191,11 @@ impl<S: Seek + ?Sized> Seek for Box<S> { fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> { (**self).seek(pos) } + + #[inline] + fn stream_position(&mut self) -> io::Result<u64> { + (**self).stream_position() + } } #[stable(feature = "rust1", since = "1.0.0")] impl<B: BufRead + ?Sized> BufRead for Box<B> { diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index 4c154dbe01a..fa073d080c6 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -252,7 +252,9 @@ mod tests; use crate::cmp; +use crate::convert::TryInto; use crate::fmt; +use crate::mem::replace; use crate::ops::{Deref, DerefMut}; use crate::ptr; use crate::slice; @@ -262,6 +264,8 @@ use crate::sys_common::memchr; #[stable(feature = "rust1", since = "1.0.0")] pub use self::buffered::IntoInnerError; +#[unstable(feature = "bufwriter_into_parts", issue = "80690")] +pub use self::buffered::WriterPanicked; #[stable(feature = "rust1", since = "1.0.0")] pub use self::buffered::{BufReader, BufWriter, LineWriter}; #[stable(feature = "rust1", since = "1.0.0")] @@ -275,6 +279,8 @@ pub use self::error::{Error, ErrorKind, Result}; pub use self::stdio::set_output_capture; #[stable(feature = "rust1", since = "1.0.0")] pub use self::stdio::{stderr, stdin, stdout, Stderr, Stdin, Stdout}; +#[unstable(feature = "stdio_locked", issue = "86845")] +pub use self::stdio::{stderr_locked, stdin_locked, stdout_locked}; #[stable(feature = "rust1", since = "1.0.0")] pub use self::stdio::{StderrLock, StdinLock, StdoutLock}; #[unstable(feature = "print_internals", issue = "none")] @@ -510,6 +516,7 @@ pub(crate) fn default_read_exact<R: Read + ?Sized>(this: &mut R, mut buf: &mut [ /// [`File`]: crate::fs::File #[stable(feature = "rust1", since = "1.0.0")] #[doc(notable_trait)] +#[cfg_attr(not(test), rustc_diagnostic_item = "IoRead")] pub trait Read { /// Pull some bytes from this source into the specified buffer, returning /// how many bytes were read. @@ -548,7 +555,7 @@ pub trait Read { /// contents of `buf` being true. It is recommended that *implementations* /// only write data to `buf` instead of reading its contents. /// - /// Correspondingly, however, *callers* of this method may not assume any guarantees + /// Correspondingly, however, *callers* of this method must not assume any guarantees /// about how the implementation uses `buf`. The trait is safe to implement, /// so it is possible that the code that's supposed to write to the buffer might also read /// from it. It is your responsibility to make sure that `buf` is initialized @@ -803,9 +810,9 @@ pub trait Read { default_read_exact(self, buf) } - /// Creates a "by reference" adaptor for this instance of `Read`. + /// Creates a "by reference" adapter for this instance of `Read`. /// - /// The returned adaptor also implements `Read` and will simply borrow this + /// The returned adapter also implements `Read` and will simply borrow this /// current reader. /// /// # Examples @@ -882,7 +889,7 @@ pub trait Read { Bytes { inner: self } } - /// Creates an adaptor which will chain this stream with another. + /// Creates an adapter which will chain this stream with another. /// /// The returned `Read` instance will first read all bytes from this object /// until EOF is encountered. Afterwards the output is equivalent to the @@ -920,7 +927,7 @@ pub trait Read { Chain { first: self, second: next, done_first: false } } - /// Creates an adaptor which will read at most `limit` bytes from it. + /// Creates an adapter which will read at most `limit` bytes from it. /// /// This function returns a new instance of `Read` which will read at most /// `limit` bytes, after which it will always return EOF ([`Ok(0)`]). Any @@ -1044,6 +1051,32 @@ impl<'a> IoSliceMut<'a> { /// Advance the internal cursor of the slice. /// + /// Also see [`IoSliceMut::advance_slices`] to advance the cursors of + /// multiple buffers. + /// + /// # Examples + /// + /// ``` + /// #![feature(io_slice_advance)] + /// + /// use std::io::IoSliceMut; + /// use std::ops::Deref; + /// + /// let mut data = [1; 8]; + /// let mut buf = IoSliceMut::new(&mut data); + /// + /// // Mark 3 bytes as read. + /// buf.advance(3); + /// assert_eq!(buf.deref(), [1; 5].as_ref()); + /// ``` + #[unstable(feature = "io_slice_advance", issue = "62726")] + #[inline] + pub fn advance(&mut self, n: usize) { + self.0.advance(n) + } + + /// Advance the internal cursor of the slices. + /// /// # Notes /// /// Elements in the slice may be modified if the cursor is not advanced to @@ -1070,13 +1103,13 @@ impl<'a> IoSliceMut<'a> { /// ][..]; /// /// // Mark 10 bytes as read. - /// bufs = IoSliceMut::advance(bufs, 10); + /// IoSliceMut::advance_slices(&mut bufs, 10); /// assert_eq!(bufs[0].deref(), [2; 14].as_ref()); /// assert_eq!(bufs[1].deref(), [3; 8].as_ref()); /// ``` #[unstable(feature = "io_slice_advance", issue = "62726")] #[inline] - pub fn advance<'b>(bufs: &'b mut [IoSliceMut<'a>], n: usize) -> &'b mut [IoSliceMut<'a>] { + pub fn advance_slices(bufs: &mut &mut [IoSliceMut<'a>], n: usize) { // Number of buffers to remove. let mut remove = 0; // Total length of all the to be removed buffers. @@ -1090,11 +1123,10 @@ impl<'a> IoSliceMut<'a> { } } - let bufs = &mut bufs[remove..]; + *bufs = &mut replace(bufs, &mut [])[remove..]; if !bufs.is_empty() { - bufs[0].0.advance(n - accumulated_len) + bufs[0].advance(n - accumulated_len) } - bufs } } @@ -1153,6 +1185,32 @@ impl<'a> IoSlice<'a> { /// Advance the internal cursor of the slice. /// + /// Also see [`IoSlice::advance_slices`] to advance the cursors of multiple + /// buffers. + /// + /// # Examples + /// + /// ``` + /// #![feature(io_slice_advance)] + /// + /// use std::io::IoSlice; + /// use std::ops::Deref; + /// + /// let mut data = [1; 8]; + /// let mut buf = IoSlice::new(&mut data); + /// + /// // Mark 3 bytes as read. + /// buf.advance(3); + /// assert_eq!(buf.deref(), [1; 5].as_ref()); + /// ``` + #[unstable(feature = "io_slice_advance", issue = "62726")] + #[inline] + pub fn advance(&mut self, n: usize) { + self.0.advance(n) + } + + /// Advance the internal cursor of the slices. + /// /// # Notes /// /// Elements in the slice may be modified if the cursor is not advanced to @@ -1179,12 +1237,12 @@ impl<'a> IoSlice<'a> { /// ][..]; /// /// // Mark 10 bytes as written. - /// bufs = IoSlice::advance(bufs, 10); + /// IoSlice::advance_slices(&mut bufs, 10); /// assert_eq!(bufs[0].deref(), [2; 14].as_ref()); /// assert_eq!(bufs[1].deref(), [3; 8].as_ref()); #[unstable(feature = "io_slice_advance", issue = "62726")] #[inline] - pub fn advance<'b>(bufs: &'b mut [IoSlice<'a>], n: usize) -> &'b mut [IoSlice<'a>] { + pub fn advance_slices(bufs: &mut &mut [IoSlice<'a>], n: usize) { // Number of buffers to remove. let mut remove = 0; // Total length of all the to be removed buffers. @@ -1198,11 +1256,10 @@ impl<'a> IoSlice<'a> { } } - let bufs = &mut bufs[remove..]; + *bufs = &mut replace(bufs, &mut [])[remove..]; if !bufs.is_empty() { - bufs[0].0.advance(n - accumulated_len) + bufs[0].advance(n - accumulated_len) } - bufs } } @@ -1269,7 +1326,7 @@ impl Initializer { /// * The [`write`] method will attempt to write some data into the object, /// returning how many bytes were successfully written. /// -/// * The [`flush`] method is useful for adaptors and explicit buffers +/// * The [`flush`] method is useful for adapters and explicit buffers /// themselves for ensuring that all buffered data has been pushed out to the /// 'true sink'. /// @@ -1307,11 +1364,12 @@ impl Initializer { /// [`write_all`]: Write::write_all #[stable(feature = "rust1", since = "1.0.0")] #[doc(notable_trait)] +#[cfg_attr(not(test), rustc_diagnostic_item = "IoWrite")] pub trait Write { /// Write a buffer into this writer, returning how many bytes were written. /// /// This function will attempt to write the entire contents of `buf`, but - /// the entire write may not succeed, or the write may also generate an + /// the entire write might not succeed, or the write may also generate an /// error. A call to `write` represents *at most one* attempt to write to /// any wrapped object. /// @@ -1364,6 +1422,27 @@ pub trait Write { /// The default implementation calls [`write`] with either the first nonempty /// buffer provided, or an empty one if none exists. /// + /// # Examples + /// + /// ```no_run + /// use std::io::IoSlice; + /// use std::io::prelude::*; + /// use std::fs::File; + /// + /// fn main() -> std::io::Result<()> { + /// let mut data1 = [1; 8]; + /// let mut data2 = [15; 8]; + /// let io_slice1 = IoSlice::new(&mut data1); + /// let io_slice2 = IoSlice::new(&mut data2); + /// + /// let mut buffer = File::create("foo.txt")?; + /// + /// // Writes some prefix of the byte string, not necessarily all of it. + /// buffer.write_vectored(&[io_slice1, io_slice2])?; + /// Ok(()) + /// } + /// ``` + /// /// [`write`]: Write::write #[stable(feature = "iovec", since = "1.36.0")] fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> Result<usize> { @@ -1511,7 +1590,7 @@ pub trait Write { fn write_all_vectored(&mut self, mut bufs: &mut [IoSlice<'_>]) -> Result<()> { // Guarantee that bufs is empty if it contains no data, // to avoid calling write_vectored if there is no data to be written. - bufs = IoSlice::advance(bufs, 0); + IoSlice::advance_slices(&mut bufs, 0); while !bufs.is_empty() { match self.write_vectored(bufs) { Ok(0) => { @@ -1520,7 +1599,7 @@ pub trait Write { &"failed to write whole buffer", )); } - Ok(n) => bufs = IoSlice::advance(bufs, n), + Ok(n) => IoSlice::advance_slices(&mut bufs, n), Err(ref e) if e.kind() == ErrorKind::Interrupted => {} Err(e) => return Err(e), } @@ -1567,12 +1646,12 @@ pub trait Write { fn write_fmt(&mut self, fmt: fmt::Arguments<'_>) -> Result<()> { // Create a shim which translates a Write to a fmt::Write and saves // off I/O errors. instead of discarding them - struct Adaptor<'a, T: ?Sized + 'a> { + struct Adapter<'a, T: ?Sized + 'a> { inner: &'a mut T, error: Result<()>, } - impl<T: Write + ?Sized> fmt::Write for Adaptor<'_, T> { + impl<T: Write + ?Sized> fmt::Write for Adapter<'_, T> { fn write_str(&mut self, s: &str) -> fmt::Result { match self.inner.write_all(s.as_bytes()) { Ok(()) => Ok(()), @@ -1584,7 +1663,7 @@ pub trait Write { } } - let mut output = Adaptor { inner: self, error: Ok(()) }; + let mut output = Adapter { inner: self, error: Ok(()) }; match fmt::write(&mut output, fmt) { Ok(()) => Ok(()), Err(..) => { @@ -1592,15 +1671,15 @@ pub trait Write { if output.error.is_err() { output.error } else { - Err(Error::new_const(ErrorKind::Other, &"formatter error")) + Err(Error::new_const(ErrorKind::Uncategorized, &"formatter error")) } } } } - /// Creates a "by reference" adaptor for this instance of `Write`. + /// Creates a "by reference" adapter for this instance of `Write`. /// - /// The returned adaptor also implements `Write` and will simply borrow this + /// The returned adapter also implements `Write` and will simply borrow this /// current writer. /// /// # Examples @@ -1684,7 +1763,6 @@ pub trait Seek { /// # Example /// /// ```no_run - /// #![feature(seek_rewind)] /// use std::io::{Read, Seek, Write}; /// use std::fs::OpenOptions; /// @@ -1702,7 +1780,7 @@ pub trait Seek { /// f.read_to_string(&mut buf).unwrap(); /// assert_eq!(&buf, hello); /// ``` - #[unstable(feature = "seek_rewind", issue = "85149")] + #[stable(feature = "seek_rewind", since = "1.55.0")] fn rewind(&mut self) -> Result<()> { self.seek(SeekFrom::Start(0))?; Ok(()) @@ -1953,6 +2031,37 @@ pub trait BufRead: Read { #[stable(feature = "rust1", since = "1.0.0")] fn consume(&mut self, amt: usize); + /// Check if the underlying `Read` has any data left to be read. + /// + /// This function may fill the buffer to check for data, + /// so this functions returns `Result<bool>`, not `bool`. + /// + /// Default implementation calls `fill_buf` and checks that + /// returned slice is empty (which means that there is no data left, + /// since EOF is reached). + /// + /// Examples + /// + /// ``` + /// #![feature(buf_read_has_data_left)] + /// use std::io; + /// use std::io::prelude::*; + /// + /// let stdin = io::stdin(); + /// let mut stdin = stdin.lock(); + /// + /// while stdin.has_data_left().unwrap() { + /// let mut line = String::new(); + /// stdin.read_line(&mut line).unwrap(); + /// // work with line + /// println!("{:?}", line); + /// } + /// ``` + #[unstable(feature = "buf_read_has_data_left", reason = "recently added", issue = "86423")] + fn has_data_left(&mut self) -> Result<bool> { + self.fill_buf().map(|b| !b.is_empty()) + } + /// Read all bytes into `buf` until the delimiter `byte` or EOF is reached. /// /// This function will read bytes from the underlying stream until the @@ -2154,7 +2263,7 @@ pub trait BufRead: Read { } } -/// Adaptor to chain together two readers. +/// Adapter to chain together two readers. /// /// This struct is generally created by calling [`chain`] on a reader. /// Please see the documentation of [`chain`] for more details. @@ -2291,19 +2400,21 @@ impl<T: BufRead, U: BufRead> BufRead for Chain<T, U> { } impl<T, U> SizeHint for Chain<T, U> { + #[inline] fn lower_bound(&self) -> usize { SizeHint::lower_bound(&self.first) + SizeHint::lower_bound(&self.second) } + #[inline] fn upper_bound(&self) -> Option<usize> { match (SizeHint::upper_bound(&self.first), SizeHint::upper_bound(&self.second)) { - (Some(first), Some(second)) => Some(first + second), + (Some(first), Some(second)) => first.checked_add(second), _ => None, } } } -/// Reader adaptor which limits the bytes read from an underlying reader. +/// Reader adapter which limits the bytes read from an underlying reader. /// /// This struct is generally created by calling [`take`] on a reader. /// Please see the documentation of [`take`] for more details. @@ -2502,6 +2613,21 @@ impl<T: BufRead> BufRead for Take<T> { } } +impl<T> SizeHint for Take<T> { + #[inline] + fn lower_bound(&self) -> usize { + cmp::min(SizeHint::lower_bound(&self.inner) as u64, self.limit) as usize + } + + #[inline] + fn upper_bound(&self) -> Option<usize> { + match SizeHint::upper_bound(&self.inner) { + Some(upper_bound) => Some(cmp::min(upper_bound as u64, self.limit) as usize), + None => self.limit.try_into().ok(), + } + } +} + /// An iterator over `u8` values of a reader. /// /// This struct is generally created by calling [`bytes`] on a reader. @@ -2546,15 +2672,53 @@ trait SizeHint { } impl<T> SizeHint for T { + #[inline] default fn lower_bound(&self) -> usize { 0 } + #[inline] default fn upper_bound(&self) -> Option<usize> { None } } +impl<T> SizeHint for &mut T { + #[inline] + fn lower_bound(&self) -> usize { + SizeHint::lower_bound(*self) + } + + #[inline] + fn upper_bound(&self) -> Option<usize> { + SizeHint::upper_bound(*self) + } +} + +impl<T> SizeHint for Box<T> { + #[inline] + fn lower_bound(&self) -> usize { + SizeHint::lower_bound(&**self) + } + + #[inline] + fn upper_bound(&self) -> Option<usize> { + SizeHint::upper_bound(&**self) + } +} + +impl SizeHint for &[u8] { + #[inline] + fn lower_bound(&self) -> usize { + self.len() + } + + #[inline] + fn upper_bound(&self) -> Option<usize> { + Some(self.len()) + } +} + /// An iterator over the contents of an instance of `BufRead` split on a /// particular byte. /// diff --git a/library/std/src/io/stdio.rs b/library/std/src/io/stdio.rs index 2b0d2b7e0be..14a63303711 100644 --- a/library/std/src/io/stdio.rs +++ b/library/std/src/io/stdio.rs @@ -7,7 +7,7 @@ use crate::io::prelude::*; use crate::cell::{Cell, RefCell}; use crate::fmt; -use crate::io::{self, BufReader, Initializer, IoSlice, IoSliceMut, LineWriter}; +use crate::io::{self, BufReader, Initializer, IoSlice, IoSliceMut, LineWriter, Lines, Split}; use crate::lazy::SyncOnceCell; use crate::pin::Pin; use crate::sync::atomic::{AtomicBool, Ordering}; @@ -216,12 +216,12 @@ fn handle_ebadf<T>(r: io::Result<T>, default: T) -> io::Result<T> { /// # Examples /// /// ```no_run -/// use std::io::{self, Read}; +/// use std::io; /// /// fn main() -> io::Result<()> { /// let mut buffer = String::new(); /// let mut stdin = io::stdin(); // We get `Stdin` here. -/// stdin.read_to_string(&mut buffer)?; +/// stdin.read_line(&mut buffer)?; /// Ok(()) /// } /// ``` @@ -244,14 +244,14 @@ pub struct Stdin { /// # Examples /// /// ```no_run -/// use std::io::{self, Read}; +/// 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_to_string(&mut buffer)?; +/// handle.read_line(&mut buffer)?; /// } // `StdinLock` is dropped here. /// Ok(()) /// } @@ -277,11 +277,11 @@ pub struct StdinLock<'a> { /// Using implicit synchronization: /// /// ```no_run -/// use std::io::{self, Read}; +/// use std::io; /// /// fn main() -> io::Result<()> { /// let mut buffer = String::new(); -/// io::stdin().read_to_string(&mut buffer)?; +/// io::stdin().read_line(&mut buffer)?; /// Ok(()) /// } /// ``` @@ -289,14 +289,14 @@ pub struct StdinLock<'a> { /// Using explicit synchronization: /// /// ```no_run -/// use std::io::{self, Read}; +/// 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_to_string(&mut buffer)?; +/// handle.read_line(&mut buffer)?; /// Ok(()) /// } /// ``` @@ -310,6 +310,48 @@ pub fn stdin() -> Stdin { } } +/// Constructs a new locked handle to the standard input of the current +/// process. +/// +/// Each handle returned is a guard granting locked access to a shared +/// global buffer whose access is synchronized via a mutex. If you need +/// more explicit control over locking, for example, in a multi-threaded +/// program, use the [`io::stdin`] function to obtain an unlocked handle, +/// along with the [`Stdin::lock`] method. +/// +/// The lock is released when the returned guard goes out of scope. The +/// returned guard also implements the [`Read`] and [`BufRead`] traits for +/// accessing the underlying data. +/// +/// **Note**: The mutex locked by this handle is not reentrant. Even in a +/// single-threaded program, calling other code that accesses [`Stdin`] +/// could cause a deadlock or panic, if this locked handle is held across +/// that call. +/// +/// ### Note: Windows Portability Consideration +/// 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. +/// +/// # Examples +/// +/// ```no_run +/// #![feature(stdio_locked)] +/// use std::io::{self, BufRead}; +/// +/// fn main() -> io::Result<()> { +/// let mut buffer = String::new(); +/// let mut handle = io::stdin_locked(); +/// +/// handle.read_line(&mut buffer)?; +/// Ok(()) +/// } +/// ``` +#[unstable(feature = "stdio_locked", issue = "86845")] +pub fn stdin_locked() -> StdinLock<'static> { + stdin().into_locked() +} + impl Stdin { /// Locks this handle to the standard input stream, returning a readable /// guard. @@ -321,20 +363,20 @@ impl Stdin { /// # Examples /// /// ```no_run - /// use std::io::{self, Read}; + /// 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_to_string(&mut buffer)?; + /// handle.read_line(&mut buffer)?; /// Ok(()) /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn lock(&self) -> StdinLock<'_> { - StdinLock { inner: self.inner.lock().unwrap_or_else(|e| e.into_inner()) } + self.lock_any() } /// Locks this handle and reads a line of input, appending it to the specified buffer. @@ -367,6 +409,86 @@ impl Stdin { pub fn read_line(&self, buf: &mut String) -> io::Result<usize> { self.lock().read_line(buf) } + + // Locks this handle with any lifetime. This depends on the + // implementation detail that the underlying `Mutex` is static. + fn lock_any<'a>(&self) -> StdinLock<'a> { + StdinLock { inner: self.inner.lock().unwrap_or_else(|e| e.into_inner()) } + } + + /// Consumes this handle to the standard input stream, locking the + /// shared global buffer associated with the stream and returning a + /// readable guard. + /// + /// The lock is released when the returned guard goes out of scope. The + /// returned guard also implements the [`Read`] and [`BufRead`] traits + /// for accessing the underlying data. + /// + /// It is often simpler to directly get a locked handle using the + /// [`stdin_locked`] function instead, unless nearby code also needs to + /// use an unlocked handle. + /// + /// # Examples + /// + /// ```no_run + /// #![feature(stdio_locked)] + /// use std::io::{self, BufRead}; + /// + /// fn main() -> io::Result<()> { + /// let mut buffer = String::new(); + /// let mut handle = io::stdin().into_locked(); + /// + /// handle.read_line(&mut buffer)?; + /// Ok(()) + /// } + /// ``` + #[unstable(feature = "stdio_locked", issue = "86845")] + pub fn into_locked(self) -> StdinLock<'static> { + self.lock_any() + } + + /// 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 + /// #![feature(stdin_forwarders)] + /// use std::io; + /// + /// let lines = io::stdin().lines(); + /// for line in lines { + /// println!("got a line: {}", line.unwrap()); + /// } + /// ``` + #[unstable(feature = "stdin_forwarders", issue = "87096")] + pub fn lines(self) -> Lines<StdinLock<'static>> { + self.into_locked().lines() + } + + /// Consumes this handle and returns an iterator over input bytes, + /// split at the specified byte value. + /// + /// For detailed semantics of this method, see the documentation on + /// [`BufRead::split`]. + /// + /// # Examples + /// + /// ```no_run + /// #![feature(stdin_forwarders)] + /// use std::io; + /// + /// let splits = io::stdin().split(b'-'); + /// for split in splits { + /// println!("got a chunk: {}", String::from_utf8_lossy(&split.unwrap())); + /// } + /// ``` + #[unstable(feature = "stdin_forwarders", issue = "87096")] + pub fn split(self, byte: u8) -> Split<StdinLock<'static>> { + self.into_locked().split(byte) + } } #[stable(feature = "std_debug", since = "1.16.0")] @@ -558,6 +680,42 @@ pub fn stdout() -> Stdout { } } +/// Constructs a new locked handle to the standard output of the current +/// process. +/// +/// Each handle returned is a guard granting locked access to a shared +/// global buffer whose access is synchronized via a mutex. If you need +/// more explicit control over locking, for example, in a multi-threaded +/// program, use the [`io::stdout`] function to obtain an unlocked handle, +/// along with the [`Stdout::lock`] method. +/// +/// The lock is released when the returned guard goes out of scope. The +/// returned guard also implements the [`Write`] trait for writing data. +/// +/// ### Note: Windows Portability Consideration +/// 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. +/// +/// # Examples +/// +/// ```no_run +/// #![feature(stdio_locked)] +/// use std::io::{self, Write}; +/// +/// fn main() -> io::Result<()> { +/// let mut handle = io::stdout_locked(); +/// +/// handle.write_all(b"hello world")?; +/// +/// Ok(()) +/// } +/// ``` +#[unstable(feature = "stdio_locked", issue = "86845")] +pub fn stdout_locked() -> StdoutLock<'static> { + stdout().into_locked() +} + pub fn cleanup() { if let Some(instance) = STDOUT.get() { // Flush the data and disable buffering during shutdown @@ -595,8 +753,45 @@ impl Stdout { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn lock(&self) -> StdoutLock<'_> { + self.lock_any() + } + + // Locks this handle with any lifetime. This depends on the + // implementation detail that the underlying `ReentrantMutex` is + // static. + fn lock_any<'a>(&self) -> StdoutLock<'a> { StdoutLock { inner: self.inner.lock() } } + + /// Consumes this handle to the standard output stream, locking the + /// shared global buffer associated with the stream and 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. + /// + /// It is often simpler to directly get a locked handle using the + /// [`io::stdout_locked`] function instead, unless nearby code also + /// needs to use an unlocked handle. + /// + /// # Examples + /// + /// ```no_run + /// #![feature(stdio_locked)] + /// use std::io::{self, Write}; + /// + /// fn main() -> io::Result<()> { + /// let mut handle = io::stdout().into_locked(); + /// + /// handle.write_all(b"hello world")?; + /// + /// Ok(()) + /// } + /// ``` + #[unstable(feature = "stdio_locked", issue = "86845")] + pub fn into_locked(self) -> StdoutLock<'static> { + self.lock_any() + } } #[stable(feature = "std_debug", since = "1.16.0")] @@ -769,6 +964,35 @@ pub fn stderr() -> Stderr { } } +/// Constructs a new locked handle to the standard error of the current +/// process. +/// +/// This handle is not buffered. +/// +/// ### Note: Windows Portability Consideration +/// 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. +/// +/// # Example +/// +/// ```no_run +/// #![feature(stdio_locked)] +/// use std::io::{self, Write}; +/// +/// fn main() -> io::Result<()> { +/// let mut handle = io::stderr_locked(); +/// +/// handle.write_all(b"hello world")?; +/// +/// Ok(()) +/// } +/// ``` +#[unstable(feature = "stdio_locked", issue = "86845")] +pub fn stderr_locked() -> StderrLock<'static> { + stderr().into_locked() +} + impl Stderr { /// Locks this handle to the standard error stream, returning a writable /// guard. @@ -792,8 +1016,42 @@ impl Stderr { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn lock(&self) -> StderrLock<'_> { + self.lock_any() + } + + // Locks this handle with any lifetime. This depends on the + // implementation detail that the underlying `ReentrantMutex` is + // static. + fn lock_any<'a>(&self) -> StderrLock<'a> { StderrLock { inner: self.inner.lock() } } + + /// Locks and consumes this handle to the standard error stream, + /// returning a writable guard. + /// + /// The lock is released when the returned guard goes out of scope. The + /// returned guard also implements the [`Write`] trait for writing + /// data. + /// + /// # Examples + /// + /// ``` + /// #![feature(stdio_locked)] + /// use std::io::{self, Write}; + /// + /// fn foo() -> io::Result<()> { + /// let stderr = io::stderr(); + /// let mut handle = stderr.into_locked(); + /// + /// handle.write_all(b"hello world")?; + /// + /// Ok(()) + /// } + /// ``` + #[unstable(feature = "stdio_locked", issue = "86845")] + pub fn into_locked(self) -> StderrLock<'static> { + self.lock_any() + } } #[stable(feature = "std_debug", since = "1.16.0")] diff --git a/library/std/src/io/stdio/tests.rs b/library/std/src/io/stdio/tests.rs index 04af500268f..b1df6b7131c 100644 --- a/library/std/src/io/stdio/tests.rs +++ b/library/std/src/io/stdio/tests.rs @@ -1,5 +1,6 @@ use super::*; use crate::panic::{RefUnwindSafe, UnwindSafe}; +use crate::sync::mpsc::sync_channel; use crate::thread; #[test] @@ -45,3 +46,121 @@ fn panic_doesnt_poison() { let _a = stderr(); let _a = _a.lock(); } + +#[test] +#[cfg_attr(target_os = "emscripten", ignore)] +fn test_lock_stderr() { + test_lock(stderr, stderr_locked); +} +#[test] +#[cfg_attr(target_os = "emscripten", ignore)] +fn test_lock_stdin() { + test_lock(stdin, stdin_locked); +} +#[test] +#[cfg_attr(target_os = "emscripten", ignore)] +fn test_lock_stdout() { + test_lock(stdout, stdout_locked); +} + +// Helper trait to make lock testing function generic. +trait Stdio<'a>: 'static +where + Self::Lock: 'a, +{ + type Lock; + fn lock(&'a self) -> Self::Lock; +} +impl<'a> Stdio<'a> for Stderr { + type Lock = StderrLock<'a>; + fn lock(&'a self) -> StderrLock<'a> { + self.lock() + } +} +impl<'a> Stdio<'a> for Stdin { + type Lock = StdinLock<'a>; + fn lock(&'a self) -> StdinLock<'a> { + self.lock() + } +} +impl<'a> Stdio<'a> for Stdout { + type Lock = StdoutLock<'a>; + fn lock(&'a self) -> StdoutLock<'a> { + self.lock() + } +} + +// Helper trait to make lock testing function generic. +trait StdioOwnedLock: 'static {} +impl StdioOwnedLock for StderrLock<'static> {} +impl StdioOwnedLock for StdinLock<'static> {} +impl StdioOwnedLock for StdoutLock<'static> {} + +// Tests locking on stdio handles by starting two threads and checking that +// they block each other appropriately. +fn test_lock<T, U>(get_handle: fn() -> T, get_locked: fn() -> U) +where + T: for<'a> Stdio<'a>, + U: StdioOwnedLock, +{ + // State enum to track different phases of the test, primarily when + // each lock is acquired and released. + #[derive(Debug, PartialEq)] + enum State { + Start1, + Acquire1, + Start2, + Release1, + Acquire2, + Release2, + } + use State::*; + // Logging vector to be checked to make sure lock acquisitions and + // releases happened in the correct order. + let log = Arc::new(Mutex::new(Vec::new())); + let ((tx1, rx1), (tx2, rx2)) = (sync_channel(0), sync_channel(0)); + let th1 = { + let (log, tx) = (Arc::clone(&log), tx1); + thread::spawn(move || { + log.lock().unwrap().push(Start1); + let handle = get_handle(); + { + let locked = handle.lock(); + log.lock().unwrap().push(Acquire1); + tx.send(Acquire1).unwrap(); // notify of acquisition + tx.send(Release1).unwrap(); // wait for release command + log.lock().unwrap().push(Release1); + } + tx.send(Acquire1).unwrap(); // wait for th2 acquire + { + let locked = handle.lock(); + log.lock().unwrap().push(Acquire1); + } + log.lock().unwrap().push(Release1); + }) + }; + let th2 = { + let (log, tx) = (Arc::clone(&log), tx2); + thread::spawn(move || { + tx.send(Start2).unwrap(); // wait for start command + let locked = get_locked(); + log.lock().unwrap().push(Acquire2); + tx.send(Acquire2).unwrap(); // notify of acquisition + tx.send(Release2).unwrap(); // wait for release command + log.lock().unwrap().push(Release2); + }) + }; + assert_eq!(rx1.recv().unwrap(), Acquire1); // wait for th1 acquire + log.lock().unwrap().push(Start2); + assert_eq!(rx2.recv().unwrap(), Start2); // block th2 + assert_eq!(rx1.recv().unwrap(), Release1); // release th1 + assert_eq!(rx2.recv().unwrap(), Acquire2); // wait for th2 acquire + assert_eq!(rx1.recv().unwrap(), Acquire1); // block th1 + assert_eq!(rx2.recv().unwrap(), Release2); // release th2 + th2.join().unwrap(); + th1.join().unwrap(); + assert_eq!( + *log.lock().unwrap(), + [Start1, Acquire1, Start2, Release1, Acquire2, Release2, Acquire1, Release1] + ); +} diff --git a/library/std/src/io/tests.rs b/library/std/src/io/tests.rs index 2b14e161503..1beb72a9a50 100644 --- a/library/std/src/io/tests.rs +++ b/library/std/src/io/tests.rs @@ -72,6 +72,16 @@ fn lines() { } #[test] +fn buf_read_has_data_left() { + let mut buf = Cursor::new(&b"abcd"[..]); + assert!(buf.has_data_left().unwrap()); + buf.read_exact(&mut [0; 2]).unwrap(); + assert!(buf.has_data_left().unwrap()); + buf.read_exact(&mut [0; 2]).unwrap(); + assert!(!buf.has_data_left().unwrap()); +} + +#[test] fn read_to_end() { let mut c = Cursor::new(&b""[..]); let mut v = Vec::new(); @@ -225,6 +235,24 @@ fn empty_size_hint() { } #[test] +fn slice_size_hint() { + let size_hint = (&[1, 2, 3]).bytes().size_hint(); + assert_eq!(size_hint, (3, Some(3))); +} + +#[test] +fn take_size_hint() { + let size_hint = (&[1, 2, 3]).take(2).bytes().size_hint(); + assert_eq!(size_hint, (2, Some(2))); + + let size_hint = (&[1, 2, 3]).take(4).bytes().size_hint(); + assert_eq!(size_hint, (3, Some(3))); + + let size_hint = io::repeat(0).take(3).bytes().size_hint(); + assert_eq!(size_hint, (3, Some(3))); +} + +#[test] fn chain_empty_size_hint() { let chain = io::empty().chain(io::empty()); let size_hint = chain.bytes().size_hint(); @@ -242,7 +270,7 @@ fn chain_size_hint() { let chain = buf_reader_1.chain(buf_reader_2); let size_hint = chain.bytes().size_hint(); - assert_eq!(size_hint, (testdata.len(), None)); + assert_eq!(size_hint, (testdata.len(), Some(testdata.len()))); } #[test] @@ -308,6 +336,10 @@ fn seek_position() -> io::Result<()> { assert_eq!(c.stream_position()?, 8); assert_eq!(c.stream_position()?, 8); + c.rewind()?; + assert_eq!(c.stream_position()?, 0); + assert_eq!(c.stream_position()?, 0); + Ok(()) } @@ -353,7 +385,7 @@ fn test_read_to_end_capacity() -> io::Result<()> { } #[test] -fn io_slice_mut_advance() { +fn io_slice_mut_advance_slices() { let mut buf1 = [1; 8]; let mut buf2 = [2; 16]; let mut buf3 = [3; 8]; @@ -364,75 +396,75 @@ fn io_slice_mut_advance() { ][..]; // Only in a single buffer.. - bufs = IoSliceMut::advance(bufs, 1); + IoSliceMut::advance_slices(&mut bufs, 1); assert_eq!(bufs[0].deref(), [1; 7].as_ref()); assert_eq!(bufs[1].deref(), [2; 16].as_ref()); assert_eq!(bufs[2].deref(), [3; 8].as_ref()); // Removing a buffer, leaving others as is. - bufs = IoSliceMut::advance(bufs, 7); + IoSliceMut::advance_slices(&mut bufs, 7); assert_eq!(bufs[0].deref(), [2; 16].as_ref()); assert_eq!(bufs[1].deref(), [3; 8].as_ref()); // Removing a buffer and removing from the next buffer. - bufs = IoSliceMut::advance(bufs, 18); + IoSliceMut::advance_slices(&mut bufs, 18); assert_eq!(bufs[0].deref(), [3; 6].as_ref()); } #[test] -fn io_slice_mut_advance_empty_slice() { - let empty_bufs = &mut [][..]; +fn io_slice_mut_advance_slices_empty_slice() { + let mut empty_bufs = &mut [][..]; // Shouldn't panic. - IoSliceMut::advance(empty_bufs, 1); + IoSliceMut::advance_slices(&mut empty_bufs, 1); } #[test] -fn io_slice_mut_advance_beyond_total_length() { +fn io_slice_mut_advance_slices_beyond_total_length() { let mut buf1 = [1; 8]; let mut bufs = &mut [IoSliceMut::new(&mut buf1)][..]; // Going beyond the total length should be ok. - bufs = IoSliceMut::advance(bufs, 9); + IoSliceMut::advance_slices(&mut bufs, 9); assert!(bufs.is_empty()); } #[test] -fn io_slice_advance() { +fn io_slice_advance_slices() { let buf1 = [1; 8]; let buf2 = [2; 16]; let buf3 = [3; 8]; let mut bufs = &mut [IoSlice::new(&buf1), IoSlice::new(&buf2), IoSlice::new(&buf3)][..]; // Only in a single buffer.. - bufs = IoSlice::advance(bufs, 1); + IoSlice::advance_slices(&mut bufs, 1); assert_eq!(bufs[0].deref(), [1; 7].as_ref()); assert_eq!(bufs[1].deref(), [2; 16].as_ref()); assert_eq!(bufs[2].deref(), [3; 8].as_ref()); // Removing a buffer, leaving others as is. - bufs = IoSlice::advance(bufs, 7); + IoSlice::advance_slices(&mut bufs, 7); assert_eq!(bufs[0].deref(), [2; 16].as_ref()); assert_eq!(bufs[1].deref(), [3; 8].as_ref()); // Removing a buffer and removing from the next buffer. - bufs = IoSlice::advance(bufs, 18); + IoSlice::advance_slices(&mut bufs, 18); assert_eq!(bufs[0].deref(), [3; 6].as_ref()); } #[test] -fn io_slice_advance_empty_slice() { - let empty_bufs = &mut [][..]; +fn io_slice_advance_slices_empty_slice() { + let mut empty_bufs = &mut [][..]; // Shouldn't panic. - IoSlice::advance(empty_bufs, 1); + IoSlice::advance_slices(&mut empty_bufs, 1); } #[test] -fn io_slice_advance_beyond_total_length() { +fn io_slice_advance_slices_beyond_total_length() { let buf1 = [1; 8]; let mut bufs = &mut [IoSlice::new(&buf1)][..]; // Going beyond the total length should be ok. - bufs = IoSlice::advance(bufs, 9); + IoSlice::advance_slices(&mut bufs, 9); assert!(bufs.is_empty()); } diff --git a/library/std/src/io/util.rs b/library/std/src/io/util.rs index 73f2f3eb3f5..a8812f197d8 100644 --- a/library/std/src/io/util.rs +++ b/library/std/src/io/util.rs @@ -13,9 +13,9 @@ use crate::io::{ /// This struct is generally created by calling [`empty()`]. Please see /// the documentation of [`empty()`] for more details. #[stable(feature = "rust1", since = "1.0.0")] -pub struct Empty { - _priv: (), -} +#[non_exhaustive] +#[derive(Copy, Clone, Default)] +pub struct Empty; /// Constructs a new handle to an empty reader. /// @@ -35,7 +35,7 @@ pub struct Empty { #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_unstable(feature = "const_io_structs", issue = "78812")] pub const fn empty() -> Empty { - Empty { _priv: () } + Empty } #[stable(feature = "rust1", since = "1.0.0")] @@ -83,6 +83,7 @@ impl fmt::Debug for Empty { } impl SizeHint for Empty { + #[inline] fn upper_bound(&self) -> Option<usize> { Some(0) } @@ -147,6 +148,18 @@ impl Read for Repeat { } } +impl SizeHint for Repeat { + #[inline] + fn lower_bound(&self) -> usize { + usize::MAX + } + + #[inline] + fn upper_bound(&self) -> Option<usize> { + None + } +} + #[stable(feature = "std_debug", since = "1.16.0")] impl fmt::Debug for Repeat { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { @@ -159,9 +172,9 @@ impl fmt::Debug for Repeat { /// This struct is generally created by calling [`sink`]. Please /// see the documentation of [`sink()`] for more details. #[stable(feature = "rust1", since = "1.0.0")] -pub struct Sink { - _priv: (), -} +#[non_exhaustive] +#[derive(Copy, Clone, Default)] +pub struct Sink; /// Creates an instance of a writer which will successfully consume all data. /// @@ -182,7 +195,7 @@ pub struct Sink { #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_unstable(feature = "const_io_structs", issue = "78812")] pub const fn sink() -> Sink { - Sink { _priv: () } + Sink } #[stable(feature = "rust1", since = "1.0.0")] diff --git a/library/std/src/keyword_docs.rs b/library/std/src/keyword_docs.rs index ba2b8b6955d..605bd33a4bf 100644 --- a/library/std/src/keyword_docs.rs +++ b/library/std/src/keyword_docs.rs @@ -971,7 +971,7 @@ mod match_keyword {} /// ``` /// /// Like [`struct`]s and [`enum`]s, a module and its content are private by -/// default, unaccessible to code outside of the module. +/// default, inaccessible to code outside of the module. /// /// To learn more about allowing access, see the documentation for the [`pub`] /// keyword. @@ -987,13 +987,13 @@ mod mod_keyword {} /// Capture a [closure]'s environment by value. /// /// `move` converts any variables captured by reference or mutable reference -/// to owned by value variables. +/// to variables captured by value. /// /// ```rust -/// let capture = "hello"; -/// let closure = move || { -/// println!("rust says {}", capture); -/// }; +/// let data = vec![1, 2, 3]; +/// let closure = move || println!("captured {:?} by value", data); +/// +/// // data is no longer available, it is owned by the closure /// ``` /// /// Note: `move` closures may still implement [`Fn`] or [`FnMut`], even though @@ -1004,31 +1004,29 @@ mod mod_keyword {} /// ```rust /// fn create_fn() -> impl Fn() { /// let text = "Fn".to_owned(); -/// /// move || println!("This is a: {}", text) /// } /// /// let fn_plain = create_fn(); -/// /// fn_plain(); /// ``` /// /// `move` is often used when [threads] are involved. /// /// ```rust -/// let x = 5; +/// let data = vec![1, 2, 3]; /// /// std::thread::spawn(move || { -/// println!("captured {} by value", x) +/// println!("captured {:?} by value", data) /// }).join().unwrap(); /// -/// // x is no longer available +/// // data was moved to the spawned thread, so we cannot use it here /// ``` /// /// `move` is also valid before an async block. /// /// ```rust -/// let capture = "hello"; +/// let capture = "hello".to_owned(); /// let block = async move { /// println!("rust says {} from async block", capture); /// }; @@ -1094,8 +1092,7 @@ mod move_keyword {} /// Mutable raw pointers work much like mutable references, with the added /// possibility of not pointing to a valid object. The syntax is `*mut Type`. /// -/// More information on mutable references and pointers can be found in``` -/// [Reference]. +/// More information on mutable references and pointers can be found in the [Reference]. /// /// [Reference]: ../reference/types/pointer.html#mutable-references-mut mod mut_keyword {} @@ -2259,6 +2256,9 @@ mod await_keyword {} /// At run-time, when a method needs to be called on the `dyn Trait`, the vtable is consulted to get /// the function pointer and then that function pointer is called. /// +/// See the Reference for more information on [trait objects][ref-trait-obj] +/// and [object safety][ref-obj-safety]. +/// /// ## Trade-offs /// /// The above indirection is the additional runtime cost of calling a function on a `dyn Trait`. @@ -2267,9 +2267,9 @@ mod await_keyword {} /// However, `dyn Trait` is likely to produce smaller code than `impl Trait` / generic parameters as /// the method won't be duplicated for each concrete type. /// -/// Read more about `object safety` and [trait object]s. -/// /// [trait object]: ../book/ch17-02-trait-objects.html +/// [ref-trait-obj]: ../reference/types/trait-object.html +/// [ref-obj-safety]: ../reference/items/traits.html#object-safety /// [erased]: https://en.wikipedia.org/wiki/Type_erasure mod dyn_keyword {} diff --git a/library/std/src/lazy.rs b/library/std/src/lazy.rs index ca86e569bc1..5afdb799f0c 100644 --- a/library/std/src/lazy.rs +++ b/library/std/src/lazy.rs @@ -86,7 +86,21 @@ impl<T: RefUnwindSafe + UnwindSafe> RefUnwindSafe for SyncOnceCell<T> {} impl<T: UnwindSafe> UnwindSafe for SyncOnceCell<T> {} #[unstable(feature = "once_cell", issue = "74465")] -impl<T> Default for SyncOnceCell<T> { +#[rustc_const_unstable(feature = "const_default_impls", issue = "87864")] +impl<T> const Default for SyncOnceCell<T> { + /// Creates a new empty cell. + /// + /// # Example + /// + /// ``` + /// #![feature(once_cell)] + /// + /// use std::lazy::SyncOnceCell; + /// + /// fn main() { + /// assert_eq!(SyncOnceCell::<()>::new(), SyncOnceCell::default()); + /// } + /// ``` fn default() -> SyncOnceCell<T> { SyncOnceCell::new() } @@ -118,6 +132,23 @@ impl<T: Clone> Clone for SyncOnceCell<T> { #[unstable(feature = "once_cell", issue = "74465")] impl<T> From<T> for SyncOnceCell<T> { + /// Create a new cell with its contents set to `value`. + /// + /// # Example + /// + /// ``` + /// #![feature(once_cell)] + /// + /// use std::lazy::SyncOnceCell; + /// + /// # fn main() -> Result<(), i32> { + /// let a = SyncOnceCell::from(3); + /// let b = SyncOnceCell::new(); + /// b.set(3)?; + /// assert_eq!(a, b); + /// Ok(()) + /// # } + /// ``` fn from(value: T) -> Self { let cell = Self::new(); match cell.set(value) { diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index c4f21587457..5e91a0cdbd6 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -225,15 +225,17 @@ #![feature(allocator_internals)] #![feature(allow_internal_unsafe)] #![feature(allow_internal_unstable)] -#![feature(async_stream)] #![feature(arbitrary_self_types)] #![feature(array_error_internals)] #![feature(asm)] #![feature(assert_matches)] #![feature(associated_type_bounds)] +#![feature(async_stream)] #![feature(atomic_mut_ptr)] +#![feature(auto_traits)] #![feature(bench_black_box)] #![feature(box_syntax)] +#![feature(c_unwind)] #![feature(c_variadic)] #![feature(cfg_accessible)] #![feature(cfg_eval)] @@ -244,14 +246,16 @@ #![feature(concat_idents)] #![feature(const_cstr_unchecked)] #![feature(const_fn_floating_point_arithmetic)] -#![feature(const_fn_transmute)] #![feature(const_fn_fn_ptr_basics)] +#![cfg_attr(bootstrap, feature(const_fn_transmute))] +#![feature(const_format_args)] #![feature(const_io_structs)] #![feature(const_ip)] +#![feature(const_ipv4)] #![feature(const_ipv6)] #![feature(const_raw_ptr_deref)] #![feature(const_socketaddr)] -#![feature(const_ipv4)] +#![feature(const_trait_impl)] #![feature(container_error_extra)] #![feature(core_intrinsics)] #![feature(custom_test_frameworks)] @@ -260,13 +264,15 @@ #![feature(doc_keyword)] #![feature(doc_masked)] #![feature(doc_notable_trait)] +#![cfg_attr(not(bootstrap), feature(doc_primitive))] #![feature(dropck_eyepatch)] +#![feature(duration_checked_float)] #![feature(duration_constants)] #![feature(edition_panic)] #![feature(exact_size_is_empty)] #![feature(exhaustive_patterns)] #![feature(extend_one)] -#![cfg_attr(bootstrap, feature(extended_key_value_attributes))] +#![feature(float_interpolation)] #![feature(fn_traits)] #![feature(format_args_nl)] #![feature(gen_future)] @@ -275,8 +281,8 @@ #![feature(global_asm)] #![feature(hashmap_internals)] #![feature(int_error_internals)] -#![feature(int_error_matching)] #![feature(integer_atomics)] +#![feature(int_log)] #![feature(into_future)] #![feature(intra_doc_pointers)] #![feature(iter_zip)] @@ -286,7 +292,6 @@ #![feature(log_syntax)] #![feature(map_try_insert)] #![feature(maybe_uninit_extra)] -#![feature(maybe_uninit_ref)] #![feature(maybe_uninit_slice)] #![feature(maybe_uninit_uninit_array)] #![feature(min_specialization)] @@ -297,19 +302,14 @@ #![feature(nll)] #![feature(nonnull_slice_from_raw_parts)] #![feature(once_cell)] -#![feature(auto_traits)] #![feature(panic_info_message)] #![feature(panic_internals)] #![feature(panic_unwind)] #![feature(pin_static_ref)] -#![feature(prelude_2021)] #![feature(prelude_import)] #![feature(ptr_internals)] -#![feature(raw)] -#![feature(ready_macro)] #![feature(rustc_attrs)] #![feature(rustc_private)] -#![feature(shrink_to)] #![feature(slice_concat_ext)] #![feature(slice_internals)] #![feature(slice_ptr_get)] @@ -327,9 +327,10 @@ #![feature(trace_macros)] #![feature(try_blocks)] #![feature(try_reserve)] +#![feature(try_reserve_kind)] #![feature(unboxed_closures)] #![feature(unsafe_cell_raw_get)] -#![feature(unwind_attributes)] +#![feature(unwrap_infallible)] #![feature(vec_into_raw_parts)] #![feature(vec_spare_capacity)] // NB: the above list is sorted to minimize merge conflicts. @@ -456,9 +457,6 @@ pub use core::pin; #[stable(feature = "rust1", since = "1.0.0")] pub use core::ptr; #[stable(feature = "rust1", since = "1.0.0")] -#[allow(deprecated, deprecated_in_future)] -pub use core::raw; -#[stable(feature = "rust1", since = "1.0.0")] pub use core::result; #[unstable(feature = "async_stream", issue = "79024")] pub use core::stream; @@ -552,17 +550,17 @@ pub use std_detect::{ #[stable(feature = "rust1", since = "1.0.0")] #[allow(deprecated, deprecated_in_future)] pub use core::{ - assert_eq, assert_matches, assert_ne, debug_assert, debug_assert_eq, debug_assert_matches, - debug_assert_ne, matches, r#try, todo, unimplemented, unreachable, write, writeln, + assert_eq, assert_ne, debug_assert, debug_assert_eq, debug_assert_ne, matches, r#try, todo, + unimplemented, unreachable, write, writeln, }; // Re-export built-in macros defined through libcore. #[stable(feature = "builtin_macro_prelude", since = "1.38.0")] #[allow(deprecated)] pub use core::{ - asm, assert, cfg, column, compile_error, concat, concat_idents, env, file, format_args, - format_args_nl, global_asm, include, include_bytes, include_str, line, llvm_asm, log_syntax, - module_path, option_env, stringify, trace_macros, + assert, assert_matches, cfg, column, compile_error, concat, concat_idents, const_format_args, + env, file, format_args, format_args_nl, include, include_bytes, include_str, line, llvm_asm, + log_syntax, module_path, option_env, stringify, trace_macros, }; #[stable(feature = "core_primitive", since = "1.43.0")] diff --git a/library/std/src/macros.rs b/library/std/src/macros.rs index b2c5df5410d..5dc75d32ec8 100644 --- a/library/std/src/macros.rs +++ b/library/std/src/macros.rs @@ -6,7 +6,7 @@ #[doc = include_str!("../../core/src/macros/panic.md")] #[macro_export] -#[rustc_builtin_macro = "std_panic"] +#[rustc_builtin_macro(std_panic)] #[stable(feature = "rust1", since = "1.0.0")] #[allow_internal_unstable(edition_panic)] #[cfg_attr(not(test), rustc_diagnostic_item = "std_panic_macro")] @@ -289,7 +289,7 @@ macro_rules! dbg { // `$val` expression could be a block (`{ .. }`), in which case the `eprintln!` // will be malformed. () => { - $crate::eprintln!("[{}:{}]", $crate::file!(), $crate::line!()); + $crate::eprintln!("[{}:{}]", $crate::file!(), $crate::line!()) }; ($val:expr $(,)?) => { // Use of `match` here is intentional because it affects the lifetimes diff --git a/library/std/src/net/addr.rs b/library/std/src/net/addr.rs index 70376d5e065..d3569710c2b 100644 --- a/library/std/src/net/addr.rs +++ b/library/std/src/net/addr.rs @@ -874,7 +874,7 @@ pub trait ToSocketAddrs { /// Converts this object to an iterator of resolved `SocketAddr`s. /// - /// The returned iterator may not actually yield any values depending on the + /// The returned iterator might not actually yield any values depending on the /// outcome of any resolution performed. /// /// Note that this function may block the current thread while resolution is diff --git a/library/std/src/net/ip.rs b/library/std/src/net/ip.rs index 6c2f2eeabd6..ac92cfe19cd 100644 --- a/library/std/src/net/ip.rs +++ b/library/std/src/net/ip.rs @@ -84,13 +84,59 @@ pub struct Ipv4Addr { /// IPv6 addresses are defined as 128-bit integers in [IETF RFC 4291]. /// They are usually represented as eight 16-bit segments. /// -/// See [`IpAddr`] for a type encompassing both IPv4 and IPv6 addresses. -/// /// The size of an `Ipv6Addr` struct may vary depending on the target operating /// system. /// /// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291 /// +/// # Embedding IPv4 Addresses +/// +/// See [`IpAddr`] for a type encompassing both IPv4 and IPv6 addresses. +/// +/// To assist in the transition from IPv4 to IPv6 two types of IPv6 addresses that embed an IPv4 address were defined: +/// IPv4-compatible and IPv4-mapped addresses. Of these IPv4-compatible addresses have been officially deprecated. +/// +/// Both types of addresses are not assigned any special meaning by this implementation, +/// other than what the relevant standards prescribe. This means that an address like `::ffff:127.0.0.1`, +/// while representing an IPv4 loopback address, is not itself an IPv6 loopback address; only `::1` is. +/// To handle these so called "IPv4-in-IPv6" addresses, they have to first be converted to their canonical IPv4 address. +/// +/// ### IPv4-Compatible IPv6 Addresses +/// +/// IPv4-compatible IPv6 addresses are defined in [IETF RFC 4291 Section 2.5.5.1], and have been officially deprecated. +/// The RFC describes the format of an "IPv4-Compatible IPv6 address" as follows: +/// +/// ```text +/// | 80 bits | 16 | 32 bits | +/// +--------------------------------------+--------------------------+ +/// |0000..............................0000|0000| IPv4 address | +/// +--------------------------------------+----+---------------------+ +/// ``` +/// So `::a.b.c.d` would be an IPv4-compatible IPv6 address representing the IPv4 address `a.b.c.d`. +/// +/// To convert from an IPv4 address to an IPv4-compatible IPv6 address, use [`Ipv4Addr::to_ipv6_compatible`]. +/// Use [`Ipv6Addr::to_ipv4`] to convert an IPv4-compatible IPv6 address to the canonical IPv4 address. +/// +/// [IETF RFC 4291 Section 2.5.5.1]: https://datatracker.ietf.org/doc/html/rfc4291#section-2.5.5.1 +/// +/// ### IPv4-Mapped IPv6 Addresses +/// +/// IPv4-mapped IPv6 addresses are defined in [IETF RFC 4291 Section 2.5.5.2]. +/// The RFC describes the format of an "IPv4-Mapped IPv6 address" as follows: +/// +/// ```text +/// | 80 bits | 16 | 32 bits | +/// +--------------------------------------+--------------------------+ +/// |0000..............................0000|FFFF| IPv4 address | +/// +--------------------------------------+----+---------------------+ +/// ``` +/// So `::ffff:a.b.c.d` would be an IPv4-mapped IPv6 address representing the IPv4 address `a.b.c.d`. +/// +/// To convert from an IPv4 address to an IPv4-mapped IPv6 address, use [`Ipv4Addr::to_ipv6_mapped`]. +/// Use [`Ipv6Addr::to_ipv4`] to convert an IPv4-mapped IPv6 address to the canonical IPv4 address. +/// +/// [IETF RFC 4291 Section 2.5.5.2]: https://datatracker.ietf.org/doc/html/rfc4291#section-2.5.5.2 +/// /// # Textual representation /// /// `Ipv6Addr` provides a [`FromStr`] implementation. There are many ways to represent @@ -116,16 +162,58 @@ pub struct Ipv6Addr { inner: c::in6_addr, } -#[allow(missing_docs)] +/// Scope of an [IPv6 multicast address] as defined in [IETF RFC 7346 section 2]. +/// +/// # Stability Guarantees +/// +/// Not all possible values for a multicast scope have been assigned. +/// Future RFCs may introduce new scopes, which will be added as variants to this enum; +/// because of this the enum is marked as `#[non_exhaustive]`. +/// +/// # Examples +/// ``` +/// #![feature(ip)] +/// +/// use std::net::Ipv6Addr; +/// use std::net::Ipv6MulticastScope::*; +/// +/// // An IPv6 multicast address with global scope (`ff0e::`). +/// let address = Ipv6Addr::new(0xff0e, 0, 0, 0, 0, 0, 0, 0); +/// +/// // Will print "Global scope". +/// match address.multicast_scope() { +/// Some(InterfaceLocal) => println!("Interface-Local scope"), +/// Some(LinkLocal) => println!("Link-Local scope"), +/// Some(RealmLocal) => println!("Realm-Local scope"), +/// Some(AdminLocal) => println!("Admin-Local scope"), +/// Some(SiteLocal) => println!("Site-Local scope"), +/// Some(OrganizationLocal) => println!("Organization-Local scope"), +/// Some(Global) => println!("Global scope"), +/// Some(_) => println!("Unknown scope"), +/// None => println!("Not a multicast address!") +/// } +/// +/// ``` +/// +/// [IPv6 multicast address]: Ipv6Addr +/// [IETF RFC 7346 section 2]: https://tools.ietf.org/html/rfc7346#section-2 #[derive(Copy, PartialEq, Eq, Clone, Hash, Debug)] #[unstable(feature = "ip", issue = "27709")] +#[non_exhaustive] pub enum Ipv6MulticastScope { + /// Interface-Local scope. InterfaceLocal, + /// Link-Local scope. LinkLocal, + /// Realm-Local scope. RealmLocal, + /// Admin-Local scope. AdminLocal, + /// Site-Local scope. SiteLocal, + /// Organization-Local scope. OrganizationLocal, + /// Global scope. Global, } @@ -291,6 +379,29 @@ impl IpAddr { pub const fn is_ipv6(&self) -> bool { matches!(self, IpAddr::V6(_)) } + + /// Converts this address to an `IpAddr::V4` if it is a IPv4-mapped IPv6 addresses, otherwise it + /// return `self` as-is. + /// + /// # Examples + /// + /// ``` + /// #![feature(ip)] + /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; + /// + /// assert_eq!(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)).to_canonical().is_loopback(), true); + /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x7f00, 0x1)).is_loopback(), false); + /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x7f00, 0x1)).to_canonical().is_loopback(), true); + /// ``` + #[inline] + #[rustc_const_unstable(feature = "const_ip", issue = "76205")] + #[unstable(feature = "ip", issue = "27709")] + pub const fn to_canonical(&self) -> IpAddr { + match self { + &v4 @ IpAddr::V4(_) => v4, + IpAddr::V6(v6) => v6.to_canonical(), + } + } } impl Ipv4Addr { @@ -314,7 +425,7 @@ impl Ipv4Addr { Ipv4Addr { inner: c::in_addr { s_addr: u32::from_ne_bytes([a, b, c, d]) } } } - /// An IPv4 address with the address pointing to localhost: 127.0.0.1. + /// An IPv4 address with the address pointing to localhost: `127.0.0.1` /// /// # Examples /// @@ -327,7 +438,7 @@ impl Ipv4Addr { #[stable(feature = "ip_constructors", since = "1.30.0")] pub const LOCALHOST: Self = Ipv4Addr::new(127, 0, 0, 1); - /// An IPv4 address representing an unspecified address: 0.0.0.0 + /// An IPv4 address representing an unspecified address: `0.0.0.0` /// /// This corresponds to the constant `INADDR_ANY` in other languages. /// @@ -343,7 +454,7 @@ impl Ipv4Addr { #[stable(feature = "ip_constructors", since = "1.30.0")] pub const UNSPECIFIED: Self = Ipv4Addr::new(0, 0, 0, 0); - /// An IPv4 address representing the broadcast address: 255.255.255.255 + /// An IPv4 address representing the broadcast address: `255.255.255.255` /// /// # Examples /// @@ -374,12 +485,12 @@ impl Ipv4Addr { self.inner.s_addr.to_ne_bytes() } - /// Returns [`true`] for the special 'unspecified' address (0.0.0.0). + /// Returns [`true`] for the special 'unspecified' address (`0.0.0.0`). /// /// This property is defined in _UNIX Network Programming, Second Edition_, /// W. Richard Stevens, p. 891; see also [ip7]. /// - /// [ip7]: http://man7.org/linux/man-pages/man7/ip.7.html + /// [ip7]: https://man7.org/linux/man-pages/man7/ip.7.html /// /// # Examples /// @@ -396,7 +507,7 @@ impl Ipv4Addr { self.inner.s_addr == 0 } - /// Returns [`true`] if this is a loopback address (127.0.0.0/8). + /// Returns [`true`] if this is a loopback address (`127.0.0.0/8`). /// /// This property is defined by [IETF RFC 1122]. /// @@ -421,9 +532,9 @@ impl Ipv4Addr { /// /// The private address ranges are defined in [IETF RFC 1918] and include: /// - /// - 10.0.0.0/8 - /// - 172.16.0.0/12 - /// - 192.168.0.0/16 + /// - `10.0.0.0/8` + /// - `172.16.0.0/12` + /// - `192.168.0.0/16` /// /// [IETF RFC 1918]: https://tools.ietf.org/html/rfc1918 /// @@ -452,7 +563,7 @@ impl Ipv4Addr { } } - /// Returns [`true`] if the address is link-local (169.254.0.0/16). + /// Returns [`true`] if the address is link-local (`169.254.0.0/16`). /// /// This property is defined by [IETF RFC 3927]. /// @@ -485,9 +596,8 @@ impl Ipv4Addr { /// - the broadcast address (see [`Ipv4Addr::is_broadcast()`]) /// - addresses used for documentation (see [`Ipv4Addr::is_documentation()`]) /// - the unspecified address (see [`Ipv4Addr::is_unspecified()`]), and the whole - /// 0.0.0.0/8 block - /// - addresses reserved for future protocols (see - /// [`Ipv4Addr::is_ietf_protocol_assignment()`], except + /// `0.0.0.0/8` block + /// - addresses reserved for future protocols, except /// `192.0.0.9/32` and `192.0.0.10/32` which are globally routable /// - addresses reserved for future use (see [`Ipv4Addr::is_reserved()`] /// - addresses reserved for networking devices benchmarking (see @@ -560,7 +670,8 @@ impl Ipv4Addr { && !self.is_broadcast() && !self.is_documentation() && !self.is_shared() - && !self.is_ietf_protocol_assignment() + // addresses reserved for future protocols (`192.0.0.0/24`) + && !(self.octets()[0] == 192 && self.octets()[1] == 0 && self.octets()[2] == 0) && !self.is_reserved() && !self.is_benchmarking() // Make sure the address is not in 0.0.0.0/8 @@ -589,40 +700,6 @@ impl Ipv4Addr { self.octets()[0] == 100 && (self.octets()[1] & 0b1100_0000 == 0b0100_0000) } - /// Returns [`true`] if this address is part of `192.0.0.0/24`, which is reserved to - /// IANA for IETF protocol assignments, as documented in [IETF RFC 6890]. - /// - /// Note that parts of this block are in use: - /// - /// - `192.0.0.8/32` is the "IPv4 dummy address" (see [IETF RFC 7600]) - /// - `192.0.0.9/32` is the "Port Control Protocol Anycast" (see [IETF RFC 7723]) - /// - `192.0.0.10/32` is used for NAT traversal (see [IETF RFC 8155]) - /// - /// [IETF RFC 6890]: https://tools.ietf.org/html/rfc6890 - /// [IETF RFC 7600]: https://tools.ietf.org/html/rfc7600 - /// [IETF RFC 7723]: https://tools.ietf.org/html/rfc7723 - /// [IETF RFC 8155]: https://tools.ietf.org/html/rfc8155 - /// - /// # Examples - /// - /// ``` - /// #![feature(ip)] - /// use std::net::Ipv4Addr; - /// - /// assert_eq!(Ipv4Addr::new(192, 0, 0, 0).is_ietf_protocol_assignment(), true); - /// assert_eq!(Ipv4Addr::new(192, 0, 0, 8).is_ietf_protocol_assignment(), true); - /// assert_eq!(Ipv4Addr::new(192, 0, 0, 9).is_ietf_protocol_assignment(), true); - /// assert_eq!(Ipv4Addr::new(192, 0, 0, 255).is_ietf_protocol_assignment(), true); - /// assert_eq!(Ipv4Addr::new(192, 0, 1, 0).is_ietf_protocol_assignment(), false); - /// assert_eq!(Ipv4Addr::new(191, 255, 255, 255).is_ietf_protocol_assignment(), false); - /// ``` - #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")] - #[unstable(feature = "ip", issue = "27709")] - #[inline] - pub const fn is_ietf_protocol_assignment(&self) -> bool { - self.octets()[0] == 192 && self.octets()[1] == 0 && self.octets()[2] == 0 - } - /// Returns [`true`] if this address part of the `198.18.0.0/15` range, which is reserved for /// network devices benchmarking. This range is defined in [IETF RFC 2544] as `192.18.0.0` /// through `198.19.255.255` but [errata 423] corrects it to `198.18.0.0/15`. @@ -682,9 +759,9 @@ impl Ipv4Addr { self.octets()[0] & 240 == 240 && !self.is_broadcast() } - /// Returns [`true`] if this is a multicast address (224.0.0.0/4). + /// Returns [`true`] if this is a multicast address (`224.0.0.0/4`). /// - /// Multicast addresses have a most significant octet between 224 and 239, + /// Multicast addresses have a most significant octet between `224` and `239`, /// and is defined by [IETF RFC 5771]. /// /// [IETF RFC 5771]: https://tools.ietf.org/html/rfc5771 @@ -705,9 +782,9 @@ impl Ipv4Addr { self.octets()[0] >= 224 && self.octets()[0] <= 239 } - /// Returns [`true`] if this is a broadcast address (255.255.255.255). + /// Returns [`true`] if this is a broadcast address (`255.255.255.255`). /// - /// A broadcast address has all octets set to 255 as defined in [IETF RFC 919]. + /// A broadcast address has all octets set to `255` as defined in [IETF RFC 919]. /// /// [IETF RFC 919]: https://tools.ietf.org/html/rfc919 /// @@ -730,9 +807,9 @@ impl Ipv4Addr { /// /// This is defined in [IETF RFC 5737]: /// - /// - 192.0.2.0/24 (TEST-NET-1) - /// - 198.51.100.0/24 (TEST-NET-2) - /// - 203.0.113.0/24 (TEST-NET-3) + /// - `192.0.2.0/24` (TEST-NET-1) + /// - `198.51.100.0/24` (TEST-NET-2) + /// - `203.0.113.0/24` (TEST-NET-3) /// /// [IETF RFC 5737]: https://tools.ietf.org/html/rfc5737 /// @@ -758,13 +835,14 @@ impl Ipv4Addr { } } - /// Converts this address to an IPv4-compatible [`IPv6` address]. + /// Converts this address to an [IPv4-compatible] [`IPv6` address]. /// - /// a.b.c.d becomes ::a.b.c.d + /// `a.b.c.d` becomes `::a.b.c.d` /// - /// This isn't typically the method you want; these addresses don't typically - /// function on modern systems. Use `to_ipv6_mapped` instead. + /// Note that IPv4-compatible addresses have been officially deprecated. + /// If you don't explicitly need an IPv4-compatible address for legacy reasons, consider using `to_ipv6_mapped` instead. /// + /// [IPv4-compatible]: Ipv6Addr#ipv4-compatible-ipv6-addresses /// [`IPv6` address]: Ipv6Addr /// /// # Examples @@ -774,7 +852,7 @@ impl Ipv4Addr { /// /// assert_eq!( /// Ipv4Addr::new(192, 0, 2, 255).to_ipv6_compatible(), - /// Ipv6Addr::new(0, 0, 0, 0, 0, 0, 49152, 767) + /// Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0xc000, 0x2ff) /// ); /// ``` #[rustc_const_stable(feature = "const_ipv4", since = "1.50.0")] @@ -787,10 +865,11 @@ impl Ipv4Addr { } } - /// Converts this address to an IPv4-mapped [`IPv6` address]. + /// Converts this address to an [IPv4-mapped] [`IPv6` address]. /// - /// a.b.c.d becomes ::ffff:a.b.c.d + /// `a.b.c.d` becomes `::ffff:a.b.c.d` /// + /// [IPv4-mapped]: Ipv6Addr#ipv4-mapped-ipv6-addresses /// [`IPv6` address]: Ipv6Addr /// /// # Examples @@ -799,7 +878,7 @@ impl Ipv4Addr { /// use std::net::{Ipv4Addr, Ipv6Addr}; /// /// assert_eq!(Ipv4Addr::new(192, 0, 2, 255).to_ipv6_mapped(), - /// Ipv6Addr::new(0, 0, 0, 0, 0, 65535, 49152, 767)); + /// Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc000, 0x2ff)); /// ``` #[rustc_const_stable(feature = "const_ipv4", since = "1.50.0")] #[stable(feature = "rust1", since = "1.0.0")] @@ -1087,7 +1166,7 @@ impl Ipv6Addr { /// /// let addr = Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff); /// ``` - #[rustc_allow_const_fn_unstable(const_fn_transmute)] + #[cfg_attr(bootstrap, rustc_allow_const_fn_unstable(const_fn_transmute))] #[rustc_const_stable(feature = "const_ipv6", since = "1.32.0")] #[stable(feature = "rust1", since = "1.0.0")] #[inline] @@ -1149,7 +1228,7 @@ impl Ipv6Addr { /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).segments(), /// [0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff]); /// ``` - #[rustc_allow_const_fn_unstable(const_fn_transmute)] + #[cfg_attr(bootstrap, rustc_allow_const_fn_unstable(const_fn_transmute))] #[rustc_const_stable(feature = "const_ipv6", since = "1.50.0")] #[stable(feature = "rust1", since = "1.0.0")] #[inline] @@ -1172,7 +1251,7 @@ impl Ipv6Addr { ] } - /// Returns [`true`] for the special 'unspecified' address (::). + /// Returns [`true`] for the special 'unspecified' address (`::`). /// /// This property is defined in [IETF RFC 4291]. /// @@ -1193,11 +1272,13 @@ impl Ipv6Addr { u128::from_be_bytes(self.octets()) == u128::from_be_bytes(Ipv6Addr::UNSPECIFIED.octets()) } - /// Returns [`true`] if this is a loopback address (::1). + /// Returns [`true`] if this is the [loopback address] (`::1`), + /// as defined in [IETF RFC 4291 section 2.5.3]. /// - /// This property is defined in [IETF RFC 4291]. + /// Contrary to IPv4, in IPv6 there is only one loopback address. /// - /// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291 + /// [loopback address]: Ipv6Addr::LOCALHOST + /// [IETF RFC 4291 section 2.5.3]: https://tools.ietf.org/html/rfc4291#section-2.5.3 /// /// # Examples /// @@ -1267,6 +1348,34 @@ impl Ipv6Addr { (self.segments()[0] & 0xfe00) == 0xfc00 } + /// Returns [`true`] if this is a unicast address, as defined by [IETF RFC 4291]. + /// Any address that is not a [multicast address] (`ff00::/8`) is unicast. + /// + /// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291 + /// [multicast address]: Ipv6Addr::is_multicast + /// + /// # Examples + /// + /// ``` + /// #![feature(ip)] + /// + /// use std::net::Ipv6Addr; + /// + /// // The unspecified and loopback addresses are unicast. + /// assert_eq!(Ipv6Addr::UNSPECIFIED.is_unicast(), true); + /// assert_eq!(Ipv6Addr::LOCALHOST.is_unicast(), true); + /// + /// // Any address that is not a multicast address (`ff00::/8`) is unicast. + /// assert_eq!(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0).is_unicast(), true); + /// assert_eq!(Ipv6Addr::new(0xff00, 0, 0, 0, 0, 0, 0, 0).is_unicast(), false); + /// ``` + #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] + #[unstable(feature = "ip", issue = "27709")] + #[inline] + pub const fn is_unicast(&self) -> bool { + !self.is_multicast() + } + /// Returns `true` if the address is a unicast address with link-local scope, /// as defined in [RFC 4291]. /// @@ -1318,47 +1427,6 @@ impl Ipv6Addr { (self.segments()[0] & 0xffc0) == 0xfe80 } - /// Returns [`true`] if this is a deprecated unicast site-local address (fec0::/10). The - /// unicast site-local address format is defined in [RFC 4291 section 2.5.7] as: - /// - /// ```no_rust - /// | 10 | - /// | bits | 54 bits | 64 bits | - /// +----------+-------------------------+----------------------------+ - /// |1111111011| subnet ID | interface ID | - /// +----------+-------------------------+----------------------------+ - /// ``` - /// - /// [RFC 4291 section 2.5.7]: https://tools.ietf.org/html/rfc4291#section-2.5.7 - /// - /// # Examples - /// - /// ``` - /// #![feature(ip)] - /// - /// use std::net::Ipv6Addr; - /// - /// assert_eq!( - /// Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_unicast_site_local(), - /// false - /// ); - /// assert_eq!(Ipv6Addr::new(0xfec2, 0, 0, 0, 0, 0, 0, 0).is_unicast_site_local(), true); - /// ``` - /// - /// # Warning - /// - /// As per [RFC 3879], the whole `FEC0::/10` prefix is - /// deprecated. New software must not support site-local - /// addresses. - /// - /// [RFC 3879]: https://tools.ietf.org/html/rfc3879 - #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] - #[unstable(feature = "ip", issue = "27709")] - #[inline] - pub const fn is_unicast_site_local(&self) -> bool { - (self.segments()[0] & 0xffc0) == 0xfec0 - } - /// Returns [`true`] if this is an address reserved for documentation /// (`2001:db8::/32`). /// @@ -1417,7 +1485,7 @@ impl Ipv6Addr { #[unstable(feature = "ip", issue = "27709")] #[inline] pub const fn is_unicast_global(&self) -> bool { - !self.is_multicast() + self.is_unicast() && !self.is_loopback() && !self.is_unicast_link_local() && !self.is_unique_local() @@ -1460,7 +1528,7 @@ impl Ipv6Addr { } } - /// Returns [`true`] if this is a multicast address (ff00::/8). + /// Returns [`true`] if this is a multicast address (`ff00::/8`). /// /// This property is defined by [IETF RFC 4291]. /// @@ -1481,13 +1549,14 @@ impl Ipv6Addr { (self.segments()[0] & 0xff00) == 0xff00 } - /// Converts this address to an [`IPv4` address] if it's an "IPv4-mapped IPv6 address" - /// defined in [IETF RFC 4291 section 2.5.5.2], otherwise returns [`None`]. + /// Converts this address to an [`IPv4` address] if it's an [IPv4-mapped] address, + /// as defined in [IETF RFC 4291 section 2.5.5.2], otherwise returns [`None`]. /// /// `::ffff:a.b.c.d` becomes `a.b.c.d`. /// All addresses *not* starting with `::ffff` will return `None`. /// /// [`IPv4` address]: Ipv4Addr + /// [IPv4-mapped]: Ipv6Addr /// [IETF RFC 4291 section 2.5.5.2]: https://tools.ietf.org/html/rfc4291#section-2.5.5.2 /// /// # Examples @@ -1514,12 +1583,19 @@ impl Ipv6Addr { } } - /// Converts this address to an [`IPv4` address]. Returns [`None`] if this address is - /// neither IPv4-compatible or IPv4-mapped. + /// Converts this address to an [`IPv4` address] if it is either + /// an [IPv4-compatible] address as defined in [IETF RFC 4291 section 2.5.5.1], + /// or an [IPv4-mapped] address as defined in [IETF RFC 4291 section 2.5.5.2], + /// otherwise returns [`None`]. /// - /// ::a.b.c.d and ::ffff:a.b.c.d become a.b.c.d + /// `::a.b.c.d` and `::ffff:a.b.c.d` become `a.b.c.d` + /// All addresses *not* starting with either all zeroes or `::ffff` will return `None`. /// - /// [`IPv4` address]: Ipv4Addr + /// [IPv4 address]: Ipv4Addr + /// [IPv4-compatible]: Ipv6Addr#ipv4-compatible-ipv6-addresses + /// [IPv4-mapped]: Ipv6Addr#ipv4-mapped-ipv6-addresses + /// [IETF RFC 4291 section 2.5.5.1]: https://tools.ietf.org/html/rfc4291#section-2.5.5.1 + /// [IETF RFC 4291 section 2.5.5.2]: https://tools.ietf.org/html/rfc4291#section-2.5.5.2 /// /// # Examples /// @@ -1545,6 +1621,28 @@ impl Ipv6Addr { } } + /// Converts this address to an `IpAddr::V4` if it is a IPv4-mapped addresses, otherwise it + /// returns self wrapped in a `IpAddr::V6`. + /// + /// # Examples + /// + /// ``` + /// #![feature(ip)] + /// use std::net::Ipv6Addr; + /// + /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x7f00, 0x1).is_loopback(), false); + /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x7f00, 0x1).to_canonical().is_loopback(), true); + /// ``` + #[inline] + #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] + #[unstable(feature = "ip", issue = "27709")] + pub const fn to_canonical(&self) -> IpAddr { + if let Some(mapped) = self.to_ipv4_mapped() { + return IpAddr::V4(mapped); + } + IpAddr::V6(*self) + } + /// Returns the sixteen eight-bit integers the IPv6 address consists of. /// /// ``` diff --git a/library/std/src/net/ip/tests.rs b/library/std/src/net/ip/tests.rs index 05f8dea0b7c..dbfab9dde40 100644 --- a/library/std/src/net/ip/tests.rs +++ b/library/std/src/net/ip/tests.rs @@ -339,7 +339,6 @@ fn ipv4_properties() { let broadcast: u16 = 1 << 6; let documentation: u16 = 1 << 7; let benchmarking: u16 = 1 << 8; - let ietf_protocol_assignment: u16 = 1 << 9; let reserved: u16 = 1 << 10; let shared: u16 = 1 << 11; @@ -397,12 +396,6 @@ fn ipv4_properties() { assert!(!ip!($s).is_benchmarking()); } - if ($mask & ietf_protocol_assignment) == ietf_protocol_assignment { - assert!(ip!($s).is_ietf_protocol_assignment()); - } else { - assert!(!ip!($s).is_ietf_protocol_assignment()); - } - if ($mask & reserved) == reserved { assert!(ip!($s).is_reserved()); } else { @@ -426,7 +419,6 @@ fn ipv4_properties() { let broadcast: u16 = 1 << 6; let documentation: u16 = 1 << 7; let benchmarking: u16 = 1 << 8; - let ietf_protocol_assignment: u16 = 1 << 9; let reserved: u16 = 1 << 10; let shared: u16 = 1 << 11; @@ -449,9 +441,9 @@ fn ipv4_properties() { check!("198.18.0.0", benchmarking); check!("198.18.54.2", benchmarking); check!("198.19.255.255", benchmarking); - check!("192.0.0.0", ietf_protocol_assignment); - check!("192.0.0.255", ietf_protocol_assignment); - check!("192.0.0.100", ietf_protocol_assignment); + check!("192.0.0.0"); + check!("192.0.0.255"); + check!("192.0.0.100"); check!("240.0.0.0", reserved); check!("251.54.1.76", reserved); check!("254.255.255.255", reserved); @@ -480,7 +472,6 @@ fn ipv6_properties() { let unique_local: u16 = 1 << 2; let global: u16 = 1 << 3; let unicast_link_local: u16 = 1 << 4; - let unicast_site_local: u16 = 1 << 6; let unicast_global: u16 = 1 << 7; let documentation: u16 = 1 << 8; let multicast_interface_local: u16 = 1 << 9; @@ -523,11 +514,6 @@ fn ipv6_properties() { } else { assert!(!ip!($s).is_unicast_link_local()); } - if ($mask & unicast_site_local) == unicast_site_local { - assert!(ip!($s).is_unicast_site_local()); - } else { - assert!(!ip!($s).is_unicast_site_local()); - } if ($mask & unicast_global) == unicast_global { assert!(ip!($s).is_unicast_global()); } else { @@ -581,7 +567,6 @@ fn ipv6_properties() { let unique_local: u16 = 1 << 2; let global: u16 = 1 << 3; let unicast_link_local: u16 = 1 << 4; - let unicast_site_local: u16 = 1 << 6; let unicast_global: u16 = 1 << 7; let documentation: u16 = 1 << 8; let multicast_interface_local: u16 = 1 << 9; @@ -651,7 +636,7 @@ fn ipv6_properties() { check!( "fec0::", &[0xfe, 0xc0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - unicast_site_local | unicast_global | global + unicast_global | global ); check!( @@ -830,9 +815,6 @@ fn ipv4_const() { const IS_SHARED: bool = IP_ADDRESS.is_shared(); assert!(!IS_SHARED); - const IS_IETF_PROTOCOL_ASSIGNMENT: bool = IP_ADDRESS.is_ietf_protocol_assignment(); - assert!(!IS_IETF_PROTOCOL_ASSIGNMENT); - const IS_BENCHMARKING: bool = IP_ADDRESS.is_benchmarking(); assert!(!IS_BENCHMARKING); @@ -889,9 +871,6 @@ fn ipv6_const() { const IS_UNICAST_LINK_LOCAL: bool = IP_ADDRESS.is_unicast_link_local(); assert!(!IS_UNICAST_LINK_LOCAL); - const IS_UNICAST_SITE_LOCAL: bool = IP_ADDRESS.is_unicast_site_local(); - assert!(!IS_UNICAST_SITE_LOCAL); - const IS_DOCUMENTATION: bool = IP_ADDRESS.is_documentation(); assert!(!IS_DOCUMENTATION); diff --git a/library/std/src/net/tcp/tests.rs b/library/std/src/net/tcp/tests.rs index abe9bc24cec..387a3617e5e 100644 --- a/library/std/src/net/tcp/tests.rs +++ b/library/std/src/net/tcp/tests.rs @@ -342,7 +342,7 @@ fn double_bind() { Err(e) => { assert!( e.kind() == ErrorKind::ConnectionRefused - || e.kind() == ErrorKind::Other + || e.kind() == ErrorKind::Uncategorized || e.kind() == ErrorKind::AddrInUse, "unknown error: {} {:?}", e, diff --git a/library/std/src/net/udp.rs b/library/std/src/net/udp.rs index 18297139b7b..d2088a12b2c 100644 --- a/library/std/src/net/udp.rs +++ b/library/std/src/net/udp.rs @@ -408,7 +408,7 @@ impl UdpSocket { /// Sets the value of the `IP_MULTICAST_LOOP` option for this socket. /// /// If enabled, multicast packets will be looped back to the local socket. - /// Note that this may not have any effect on IPv6 sockets. + /// Note that this might not have any effect on IPv6 sockets. /// /// # Examples /// @@ -447,7 +447,7 @@ impl UdpSocket { /// this socket. The default value is 1 which means that multicast packets /// don't leave the local network unless explicitly requested. /// - /// Note that this may not have any effect on IPv6 sockets. + /// Note that this might not have any effect on IPv6 sockets. /// /// # Examples /// @@ -483,7 +483,7 @@ impl UdpSocket { /// Sets the value of the `IPV6_MULTICAST_LOOP` option for this socket. /// /// Controls whether this socket sees the multicast packets it sends itself. - /// Note that this may not have any affect on IPv4 sockets. + /// Note that this might not have any affect on IPv4 sockets. /// /// # Examples /// diff --git a/library/std/src/num.rs b/library/std/src/num.rs index 0f1c5962685..e7051f0ce95 100644 --- a/library/std/src/num.rs +++ b/library/std/src/num.rs @@ -22,12 +22,7 @@ pub use core::num::{NonZeroI128, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, #[stable(feature = "nonzero", since = "1.28.0")] pub use core::num::{NonZeroU128, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize}; -#[unstable( - feature = "int_error_matching", - reason = "it can be useful to match errors when making error messages \ - for integer parsing", - issue = "22639" -)] +#[stable(feature = "int_error_matching", since = "1.55.0")] pub use core::num::IntErrorKind; #[cfg(test)] diff --git a/library/std/src/os/espidf/fs.rs b/library/std/src/os/espidf/fs.rs new file mode 100644 index 00000000000..93dc2c0cab7 --- /dev/null +++ b/library/std/src/os/espidf/fs.rs @@ -0,0 +1,117 @@ +#![stable(feature = "metadata_ext", since = "1.1.0")] + +use crate::fs::Metadata; +use crate::sys_common::AsInner; + +#[allow(deprecated)] +use crate::os::espidf::raw; + +/// OS-specific extensions to [`fs::Metadata`]. +/// +/// [`fs::Metadata`]: crate::fs::Metadata +#[stable(feature = "metadata_ext", since = "1.1.0")] +pub trait MetadataExt { + #[stable(feature = "metadata_ext", since = "1.1.0")] + #[rustc_deprecated( + since = "1.8.0", + reason = "deprecated in favor of the accessor \ + methods of this trait" + )] + #[allow(deprecated)] + fn as_raw_stat(&self) -> &raw::stat; + + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_dev(&self) -> u64; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_ino(&self) -> u64; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_mode(&self) -> u32; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_nlink(&self) -> u64; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_uid(&self) -> u32; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_gid(&self) -> u32; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_rdev(&self) -> u64; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_size(&self) -> u64; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_atime(&self) -> i64; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_atime_nsec(&self) -> i64; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_mtime(&self) -> i64; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_mtime_nsec(&self) -> i64; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_ctime(&self) -> i64; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_ctime_nsec(&self) -> i64; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_blksize(&self) -> u64; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_blocks(&self) -> u64; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_spare4(&self) -> [u32; 2]; +} + +#[stable(feature = "metadata_ext", since = "1.1.0")] +impl MetadataExt for Metadata { + #[allow(deprecated)] + fn as_raw_stat(&self) -> &raw::stat { + unsafe { &*(self.as_inner().as_inner() as *const libc::stat as *const raw::stat) } + } + fn st_dev(&self) -> u64 { + self.as_inner().as_inner().st_dev as u64 + } + fn st_ino(&self) -> u64 { + self.as_inner().as_inner().st_ino as u64 + } + fn st_mode(&self) -> u32 { + self.as_inner().as_inner().st_mode as u32 + } + fn st_nlink(&self) -> u64 { + self.as_inner().as_inner().st_nlink as u64 + } + fn st_uid(&self) -> u32 { + self.as_inner().as_inner().st_uid as u32 + } + fn st_gid(&self) -> u32 { + self.as_inner().as_inner().st_gid as u32 + } + fn st_rdev(&self) -> u64 { + self.as_inner().as_inner().st_rdev as u64 + } + fn st_size(&self) -> u64 { + self.as_inner().as_inner().st_size as u64 + } + fn st_atime(&self) -> i64 { + self.as_inner().as_inner().st_atime as i64 + } + fn st_atime_nsec(&self) -> i64 { + 0 + } + fn st_mtime(&self) -> i64 { + self.as_inner().as_inner().st_mtime as i64 + } + fn st_mtime_nsec(&self) -> i64 { + 0 + } + fn st_ctime(&self) -> i64 { + self.as_inner().as_inner().st_ctime as i64 + } + fn st_ctime_nsec(&self) -> i64 { + 0 + } + fn st_blksize(&self) -> u64 { + self.as_inner().as_inner().st_blksize as u64 + } + fn st_blocks(&self) -> u64 { + self.as_inner().as_inner().st_blocks as u64 + } + fn st_spare4(&self) -> [u32; 2] { + let spare4 = self.as_inner().as_inner().st_spare4; + [spare4[0] as u32, spare4[1] as u32] + } +} diff --git a/library/std/src/os/espidf/mod.rs b/library/std/src/os/espidf/mod.rs new file mode 100644 index 00000000000..a9cef970930 --- /dev/null +++ b/library/std/src/os/espidf/mod.rs @@ -0,0 +1,6 @@ +//! Definitions for the ESP-IDF framework. + +#![stable(feature = "raw_ext", since = "1.1.0")] + +pub mod fs; +pub mod raw; diff --git a/library/std/src/os/espidf/raw.rs b/library/std/src/os/espidf/raw.rs new file mode 100644 index 00000000000..fb18ec6f6f8 --- /dev/null +++ b/library/std/src/os/espidf/raw.rs @@ -0,0 +1,69 @@ +//! Raw type definitions for the ESP-IDF framework. + +#![stable(feature = "raw_ext", since = "1.1.0")] +#![rustc_deprecated( + since = "1.8.0", + reason = "these type aliases are no longer supported by \ + the standard library, the `libc` crate on \ + crates.io should be used instead for the correct \ + definitions" +)] + +use crate::os::raw::c_long; +use crate::os::unix::raw::{gid_t, uid_t}; + +#[stable(feature = "pthread_t", since = "1.8.0")] +pub type pthread_t = libc::pthread_t; + +#[stable(feature = "raw_ext", since = "1.1.0")] +pub type blkcnt_t = libc::blkcnt_t; + +#[stable(feature = "raw_ext", since = "1.1.0")] +pub type blksize_t = libc::blksize_t; +#[stable(feature = "raw_ext", since = "1.1.0")] +pub type dev_t = libc::dev_t; +#[stable(feature = "raw_ext", since = "1.1.0")] +pub type ino_t = libc::ino_t; +#[stable(feature = "raw_ext", since = "1.1.0")] +pub type mode_t = libc::mode_t; +#[stable(feature = "raw_ext", since = "1.1.0")] +pub type nlink_t = libc::nlink_t; +#[stable(feature = "raw_ext", since = "1.1.0")] +pub type off_t = libc::off_t; + +#[stable(feature = "raw_ext", since = "1.1.0")] +pub type time_t = libc::time_t; + +#[repr(C)] +#[derive(Clone)] +#[stable(feature = "raw_ext", since = "1.1.0")] +pub struct stat { + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_dev: dev_t, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_ino: ino_t, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_mode: mode_t, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_nlink: nlink_t, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_uid: uid_t, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_gid: gid_t, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_rdev: dev_t, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_size: off_t, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_atime: time_t, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_mtime: time_t, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_ctime: time_t, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_blksize: blksize_t, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_blocks: blkcnt_t, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_spare4: [c_long; 2usize], +} diff --git a/library/std/src/os/fortanix_sgx/arch.rs b/library/std/src/os/fortanix_sgx/arch.rs index b0170e67446..4ce482e23cb 100644 --- a/library/std/src/os/fortanix_sgx/arch.rs +++ b/library/std/src/os/fortanix_sgx/arch.rs @@ -33,13 +33,13 @@ pub fn egetkey(request: &Align512<[u8; 512]>) -> Result<Align16<[u8; 16]>, u32> asm!( // rbx is reserved by LLVM - "xchg {0}, rbx", + "xchg %rbx, {0}", "enclu", - "mov rbx, {0}", + "mov {0}, %rbx", inout(reg) request => _, inlateout("eax") ENCLU_EGETKEY => error, in("rcx") out.as_mut_ptr(), - options(nostack), + options(att_syntax, nostack), ); match error { @@ -64,14 +64,14 @@ pub fn ereport( asm!( // rbx is reserved by LLVM - "xchg {0}, rbx", + "xchg %rbx, {0}", "enclu", - "mov rbx, {0}", + "mov {0}, %rbx", inout(reg) targetinfo => _, in("eax") ENCLU_EREPORT, in("rcx") reportdata, in("rdx") report.as_mut_ptr(), - options(preserves_flags, nostack), + options(att_syntax, preserves_flags, nostack), ); report.assume_init() diff --git a/library/std/src/os/fortanix_sgx/ffi.rs b/library/std/src/os/fortanix_sgx/ffi.rs index 63fc5ff2866..ac1db0e5e39 100644 --- a/library/std/src/os/fortanix_sgx/ffi.rs +++ b/library/std/src/os/fortanix_sgx/ffi.rs @@ -34,5 +34,8 @@ #![unstable(feature = "sgx_platform", issue = "56975")] +#[path = "../unix/ffi/os_str.rs"] +mod os_str; + #[unstable(feature = "sgx_platform", issue = "56975")] -pub use crate::sys_common::os_str_bytes::*; +pub use self::os_str::{OsStrExt, OsStringExt}; diff --git a/library/std/src/os/hermit/ffi.rs b/library/std/src/os/hermit/ffi.rs index 07b59a02556..19761fd99b4 100644 --- a/library/std/src/os/hermit/ffi.rs +++ b/library/std/src/os/hermit/ffi.rs @@ -34,5 +34,8 @@ #![stable(feature = "rust1", since = "1.0.0")] +#[path = "../unix/ffi/os_str.rs"] +mod os_str; + #[stable(feature = "rust1", since = "1.0.0")] -pub use crate::sys_common::os_str_bytes::*; +pub use self::os_str::{OsStrExt, OsStringExt}; diff --git a/library/std/src/os/linux/mod.rs b/library/std/src/os/linux/mod.rs index 94438defc22..8e7776f6646 100644 --- a/library/std/src/os/linux/mod.rs +++ b/library/std/src/os/linux/mod.rs @@ -4,4 +4,5 @@ #![doc(cfg(target_os = "linux"))] pub mod fs; +pub mod process; pub mod raw; diff --git a/library/std/src/os/linux/process.rs b/library/std/src/os/linux/process.rs new file mode 100644 index 00000000000..6daff0f003c --- /dev/null +++ b/library/std/src/os/linux/process.rs @@ -0,0 +1,145 @@ +//! Linux-specific extensions to primitives in the `std::process` module. + +#![unstable(feature = "linux_pidfd", issue = "82971")] + +use crate::io::Result; +use crate::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; +use crate::process; +use crate::sealed::Sealed; +#[cfg(not(doc))] +use crate::sys::fd::FileDesc; +use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner}; + +#[cfg(doc)] +struct FileDesc; + +/// This type represents a file descriptor that refers to a process. +/// +/// A `PidFd` can be obtained by setting the corresponding option on [`Command`] +/// with [`create_pidfd`]. Subsequently, the created pidfd can be retrieved +/// from the [`Child`] by calling [`pidfd`] or [`take_pidfd`]. +/// +/// Example: +/// ```no_run +/// #![feature(linux_pidfd)] +/// use std::os::linux::process::{CommandExt, ChildExt}; +/// use std::process::Command; +/// +/// let mut child = Command::new("echo") +/// .create_pidfd(true) +/// .spawn() +/// .expect("Failed to spawn child"); +/// +/// let pidfd = child +/// .take_pidfd() +/// .expect("Failed to retrieve pidfd"); +/// +/// // The file descriptor will be closed when `pidfd` is dropped. +/// ``` +/// Refer to the man page of [`pidfd_open(2)`] for further details. +/// +/// [`Command`]: process::Command +/// [`create_pidfd`]: CommandExt::create_pidfd +/// [`Child`]: process::Child +/// [`pidfd`]: fn@ChildExt::pidfd +/// [`take_pidfd`]: ChildExt::take_pidfd +/// [`pidfd_open(2)`]: https://man7.org/linux/man-pages/man2/pidfd_open.2.html +#[derive(Debug)] +pub struct PidFd { + inner: FileDesc, +} + +impl AsInner<FileDesc> for PidFd { + fn as_inner(&self) -> &FileDesc { + &self.inner + } +} + +impl FromInner<FileDesc> for PidFd { + fn from_inner(inner: FileDesc) -> PidFd { + PidFd { inner } + } +} + +impl IntoInner<FileDesc> for PidFd { + fn into_inner(self) -> FileDesc { + self.inner + } +} + +impl AsRawFd for PidFd { + fn as_raw_fd(&self) -> RawFd { + self.as_inner().raw() + } +} + +impl FromRawFd for PidFd { + unsafe fn from_raw_fd(fd: RawFd) -> Self { + Self::from_inner(FileDesc::new(fd)) + } +} + +impl IntoRawFd for PidFd { + fn into_raw_fd(self) -> RawFd { + self.into_inner().into_raw() + } +} + +/// Os-specific extensions for [`Child`] +/// +/// [`Child`]: process::Child +pub trait ChildExt: Sealed { + /// Obtains a reference to the [`PidFd`] created for this [`Child`], if available. + /// + /// A pidfd will only be available if its creation was requested with + /// [`create_pidfd`] when the corresponding [`Command`] was created. + /// + /// Even if requested, a pidfd may not be available due to an older + /// version of Linux being in use, or if some other error occurred. + /// + /// [`Command`]: process::Command + /// [`create_pidfd`]: CommandExt::create_pidfd + /// [`Child`]: process::Child + fn pidfd(&self) -> Result<&PidFd>; + + /// Takes ownership of the [`PidFd`] created for this [`Child`], if available. + /// + /// A pidfd will only be available if its creation was requested with + /// [`create_pidfd`] when the corresponding [`Command`] was created. + /// + /// Even if requested, a pidfd may not be available due to an older + /// version of Linux being in use, or if some other error occurred. + /// + /// [`Command`]: process::Command + /// [`create_pidfd`]: CommandExt::create_pidfd + /// [`Child`]: process::Child + fn take_pidfd(&mut self) -> Result<PidFd>; +} + +/// Os-specific extensions for [`Command`] +/// +/// [`Command`]: process::Command +pub trait CommandExt: Sealed { + /// Sets whether a [`PidFd`](struct@PidFd) should be created for the [`Child`] + /// spawned by this [`Command`]. + /// By default, no pidfd will be created. + /// + /// The pidfd can be retrieved from the child with [`pidfd`] or [`take_pidfd`]. + /// + /// A pidfd will only be created if it is possible to do so + /// in a guaranteed race-free manner (e.g. if the `clone3` system call + /// is supported). Otherwise, [`pidfd`] will return an error. + /// + /// [`Command`]: process::Command + /// [`Child`]: process::Child + /// [`pidfd`]: fn@ChildExt::pidfd + /// [`take_pidfd`]: ChildExt::take_pidfd + fn create_pidfd(&mut self, val: bool) -> &mut process::Command; +} + +impl CommandExt for process::Command { + fn create_pidfd(&mut self, val: bool) -> &mut process::Command { + self.as_inner_mut().create_pidfd(val); + self + } +} diff --git a/library/std/src/os/mod.rs b/library/std/src/os/mod.rs index 07e29ebf368..4c9814919cd 100644 --- a/library/std/src/os/mod.rs +++ b/library/std/src/os/mod.rs @@ -80,6 +80,8 @@ mod imp { pub mod dragonfly; #[cfg(target_os = "emscripten")] pub mod emscripten; + #[cfg(target_os = "espidf")] + pub mod espidf; #[cfg(target_os = "freebsd")] pub mod freebsd; #[cfg(target_os = "fuchsia")] diff --git a/library/std/src/os/unix/ffi.rs b/library/std/src/os/unix/ffi/mod.rs index 123f85deaf9..c29df6596fd 100644 --- a/library/std/src/os/unix/ffi.rs +++ b/library/std/src/os/unix/ffi/mod.rs @@ -34,5 +34,7 @@ #![stable(feature = "rust1", since = "1.0.0")] +mod os_str; + #[stable(feature = "rust1", since = "1.0.0")] -pub use crate::sys_common::os_str_bytes::*; +pub use self::os_str::{OsStrExt, OsStringExt}; diff --git a/library/std/src/os/unix/ffi/os_str.rs b/library/std/src/os/unix/ffi/os_str.rs new file mode 100644 index 00000000000..54c9a9382f2 --- /dev/null +++ b/library/std/src/os/unix/ffi/os_str.rs @@ -0,0 +1,68 @@ +use crate::ffi::{OsStr, OsString}; +use crate::mem; +use crate::sealed::Sealed; +use crate::sys::os_str::Buf; +use crate::sys_common::{AsInner, FromInner, IntoInner}; + +// Note: this file is currently reused in other `std::os::{platform}::ffi` modules to reduce duplication. +// Keep this in mind when applying changes to this file that only apply to `unix`. + +/// Platform-specific extensions to [`OsString`]. +/// +/// This trait is sealed: it cannot be implemented outside the standard library. +/// This is so that future additional methods are not breaking changes. +#[stable(feature = "rust1", since = "1.0.0")] +pub trait OsStringExt: Sealed { + /// Creates an [`OsString`] from a byte vector. + /// + /// See the module documentation for an example. + #[stable(feature = "rust1", since = "1.0.0")] + fn from_vec(vec: Vec<u8>) -> Self; + + /// Yields the underlying byte vector of this [`OsString`]. + /// + /// See the module documentation for an example. + #[stable(feature = "rust1", since = "1.0.0")] + fn into_vec(self) -> Vec<u8>; +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl OsStringExt for OsString { + fn from_vec(vec: Vec<u8>) -> OsString { + FromInner::from_inner(Buf { inner: vec }) + } + fn into_vec(self) -> Vec<u8> { + self.into_inner().inner + } +} + +/// Platform-specific extensions to [`OsStr`]. +/// +/// This trait is sealed: it cannot be implemented outside the standard library. +/// This is so that future additional methods are not breaking changes. +#[stable(feature = "rust1", since = "1.0.0")] +pub trait OsStrExt: Sealed { + #[stable(feature = "rust1", since = "1.0.0")] + /// Creates an [`OsStr`] from a byte slice. + /// + /// See the module documentation for an example. + fn from_bytes(slice: &[u8]) -> &Self; + + /// Gets the underlying byte view of the [`OsStr`] slice. + /// + /// See the module documentation for an example. + #[stable(feature = "rust1", since = "1.0.0")] + fn as_bytes(&self) -> &[u8]; +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl OsStrExt for OsStr { + #[inline] + fn from_bytes(slice: &[u8]) -> &OsStr { + unsafe { mem::transmute(slice) } + } + #[inline] + fn as_bytes(&self) -> &[u8] { + &self.as_inner().inner + } +} diff --git a/library/std/src/os/unix/fs.rs b/library/std/src/os/unix/fs.rs index 913c71d4108..e4ce788f741 100644 --- a/library/std/src/os/unix/fs.rs +++ b/library/std/src/os/unix/fs.rs @@ -9,6 +9,8 @@ use crate::path::Path; use crate::sys; use crate::sys_common::{AsInner, AsInnerMut, FromInner}; // Used for `File::read` on intra-doc links +use crate::ffi::OsStr; +use crate::sealed::Sealed; #[allow(unused_imports)] use io::{Read, Write}; @@ -839,6 +841,43 @@ impl DirEntryExt for fs::DirEntry { } } +/// Sealed Unix-specific extension methods for [`fs::DirEntry`]. +#[unstable(feature = "dir_entry_ext2", issue = "85573")] +pub trait DirEntryExt2: Sealed { + /// Returns a reference to the underlying `OsStr` of this entry's filename. + /// + /// # Examples + /// + /// ``` + /// #![feature(dir_entry_ext2)] + /// use std::os::unix::fs::DirEntryExt2; + /// use std::{fs, io}; + /// + /// fn main() -> io::Result<()> { + /// let mut entries = fs::read_dir(".")?.collect::<Result<Vec<_>, io::Error>>()?; + /// entries.sort_unstable_by(|a, b| a.file_name_ref().cmp(b.file_name_ref())); + /// + /// for p in entries { + /// println!("{:?}", p); + /// } + /// + /// Ok(()) + /// } + /// ``` + fn file_name_ref(&self) -> &OsStr; +} + +/// Allows extension traits within `std`. +#[unstable(feature = "sealed", issue = "none")] +impl Sealed for fs::DirEntry {} + +#[unstable(feature = "dir_entry_ext2", issue = "85573")] +impl DirEntryExt2 for fs::DirEntry { + fn file_name_ref(&self) -> &OsStr { + self.as_inner().file_name_os_str() + } +} + /// Creates a new symbolic link on the filesystem. /// /// The `link` path will be a symbolic link pointing to the `original` path. diff --git a/library/std/src/os/unix/mod.rs b/library/std/src/os/unix/mod.rs index 6fc1c89a2ba..6c73d4b21dd 100644 --- a/library/std/src/os/unix/mod.rs +++ b/library/std/src/os/unix/mod.rs @@ -40,6 +40,8 @@ mod platform { pub use crate::os::dragonfly::*; #[cfg(target_os = "emscripten")] pub use crate::os::emscripten::*; + #[cfg(target_os = "espidf")] + pub use crate::os::espidf::*; #[cfg(target_os = "freebsd")] pub use crate::os::freebsd::*; #[cfg(target_os = "fuchsia")] @@ -82,6 +84,7 @@ pub mod thread; target_os = "freebsd", target_os = "ios", target_os = "macos", + target_os = "netbsd", target_os = "openbsd" ))] pub mod ucred; diff --git a/library/std/src/os/unix/net/addr.rs b/library/std/src/os/unix/net/addr.rs index 459f3590e64..62bfde8bfd4 100644 --- a/library/std/src/os/unix/net/addr.rs +++ b/library/std/src/os/unix/net/addr.rs @@ -31,7 +31,7 @@ pub(super) unsafe fn sockaddr_un(path: &Path) -> io::Result<(libc::sockaddr_un, if bytes.contains(&0) { return Err(io::Error::new_const( io::ErrorKind::InvalidInput, - &"paths may not contain interior null bytes", + &"paths must not contain interior null bytes", )); } diff --git a/library/std/src/os/unix/net/ancillary.rs b/library/std/src/os/unix/net/ancillary.rs index 15ce7056fea..cd429d14269 100644 --- a/library/std/src/os/unix/net/ancillary.rs +++ b/library/std/src/os/unix/net/ancillary.rs @@ -32,23 +32,8 @@ pub(super) fn recv_vectored_with_ancillary_from( msg.msg_name = &mut msg_name as *mut _ as *mut _; msg.msg_namelen = size_of::<libc::sockaddr_un>() as libc::socklen_t; msg.msg_iov = bufs.as_mut_ptr().cast(); - cfg_if::cfg_if! { - if #[cfg(any(target_os = "android", all(target_os = "linux", target_env = "gnu")))] { - msg.msg_iovlen = bufs.len() as libc::size_t; - msg.msg_controllen = ancillary.buffer.len() as libc::size_t; - } else if #[cfg(any( - target_os = "dragonfly", - target_os = "emscripten", - target_os = "freebsd", - all(target_os = "linux", target_env = "musl",), - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd", - ))] { - msg.msg_iovlen = bufs.len() as libc::c_int; - msg.msg_controllen = ancillary.buffer.len() as libc::socklen_t; - } - } + msg.msg_iovlen = bufs.len() as _; + msg.msg_controllen = ancillary.buffer.len() as _; // macos requires that the control pointer is null when the len is 0. if msg.msg_controllen > 0 { msg.msg_control = ancillary.buffer.as_mut_ptr().cast(); @@ -80,23 +65,8 @@ pub(super) fn send_vectored_with_ancillary_to( msg.msg_name = &mut msg_name as *mut _ as *mut _; msg.msg_namelen = msg_namelen; msg.msg_iov = bufs.as_ptr() as *mut _; - cfg_if::cfg_if! { - if #[cfg(any(target_os = "android", all(target_os = "linux", target_env = "gnu")))] { - msg.msg_iovlen = bufs.len() as libc::size_t; - msg.msg_controllen = ancillary.length as libc::size_t; - } else if #[cfg(any( - target_os = "dragonfly", - target_os = "emscripten", - target_os = "freebsd", - all(target_os = "linux", target_env = "musl",), - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd", - ))] { - msg.msg_iovlen = bufs.len() as libc::c_int; - msg.msg_controllen = ancillary.length as libc::socklen_t; - } - } + msg.msg_iovlen = bufs.len() as _; + msg.msg_controllen = ancillary.length as _; // macos requires that the control pointer is null when the len is 0. if msg.msg_controllen > 0 { msg.msg_control = ancillary.buffer.as_mut_ptr().cast(); @@ -144,21 +114,7 @@ fn add_to_ancillary_data<T>( let mut msg: libc::msghdr = zeroed(); msg.msg_control = buffer.as_mut_ptr().cast(); - cfg_if::cfg_if! { - if #[cfg(any(target_os = "android", all(target_os = "linux", target_env = "gnu")))] { - msg.msg_controllen = *length as libc::size_t; - } else if #[cfg(any( - target_os = "dragonfly", - target_os = "emscripten", - target_os = "freebsd", - all(target_os = "linux", target_env = "musl",), - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd", - ))] { - msg.msg_controllen = *length as libc::socklen_t; - } - } + msg.msg_controllen = *length as _; let mut cmsg = libc::CMSG_FIRSTHDR(&msg); let mut previous_cmsg = cmsg; @@ -180,21 +136,7 @@ fn add_to_ancillary_data<T>( (*previous_cmsg).cmsg_level = cmsg_level; (*previous_cmsg).cmsg_type = cmsg_type; - cfg_if::cfg_if! { - if #[cfg(any(target_os = "android", all(target_os = "linux", target_env = "gnu")))] { - (*previous_cmsg).cmsg_len = libc::CMSG_LEN(source_len) as libc::size_t; - } else if #[cfg(any( - target_os = "dragonfly", - target_os = "emscripten", - target_os = "freebsd", - all(target_os = "linux", target_env = "musl",), - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd", - ))] { - (*previous_cmsg).cmsg_len = libc::CMSG_LEN(source_len) as libc::socklen_t; - } - } + (*previous_cmsg).cmsg_len = libc::CMSG_LEN(source_len) as _; let data = libc::CMSG_DATA(previous_cmsg).cast(); @@ -364,28 +306,10 @@ impl<'a> AncillaryData<'a> { fn try_from_cmsghdr(cmsg: &'a libc::cmsghdr) -> Result<Self, AncillaryError> { unsafe { - cfg_if::cfg_if! { - if #[cfg(any( - target_os = "android", - all(target_os = "linux", target_env = "gnu"), - all(target_os = "linux", target_env = "uclibc"), - ))] { - let cmsg_len_zero = libc::CMSG_LEN(0) as libc::size_t; - } else if #[cfg(any( - target_os = "dragonfly", - target_os = "emscripten", - target_os = "freebsd", - all(target_os = "linux", target_env = "musl",), - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd", - ))] { - let cmsg_len_zero = libc::CMSG_LEN(0) as libc::socklen_t; - } - } - let data_len = (*cmsg).cmsg_len - cmsg_len_zero; + let cmsg_len_zero = libc::CMSG_LEN(0) as usize; + let data_len = (*cmsg).cmsg_len as usize - cmsg_len_zero; let data = libc::CMSG_DATA(cmsg).cast(); - let data = from_raw_parts(data, data_len as usize); + let data = from_raw_parts(data, data_len); match (*cmsg).cmsg_level { libc::SOL_SOCKET => match (*cmsg).cmsg_type { @@ -419,21 +343,7 @@ impl<'a> Iterator for Messages<'a> { unsafe { let mut msg: libc::msghdr = zeroed(); msg.msg_control = self.buffer.as_ptr() as *mut _; - cfg_if::cfg_if! { - if #[cfg(any(target_os = "android", all(target_os = "linux", target_env = "gnu")))] { - msg.msg_controllen = self.buffer.len() as libc::size_t; - } else if #[cfg(any( - target_os = "dragonfly", - target_os = "emscripten", - target_os = "freebsd", - all(target_os = "linux", target_env = "musl",), - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd", - ))] { - msg.msg_controllen = self.buffer.len() as libc::socklen_t; - } - } + msg.msg_controllen = self.buffer.len() as _; let cmsg = if let Some(current) = self.current { libc::CMSG_NXTHDR(&msg, current) diff --git a/library/std/src/os/unix/net/stream.rs b/library/std/src/os/unix/net/stream.rs index a6f6e091305..fba084375e5 100644 --- a/library/std/src/os/unix/net/stream.rs +++ b/library/std/src/os/unix/net/stream.rs @@ -21,6 +21,7 @@ use crate::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; target_os = "freebsd", target_os = "ios", target_os = "macos", + target_os = "netbsd", target_os = "openbsd" ))] use crate::os::unix::ucred; @@ -38,6 +39,7 @@ use crate::time::Duration; target_os = "freebsd", target_os = "ios", target_os = "macos", + target_os = "netbsd", target_os = "openbsd" ))] pub use ucred::UCred; @@ -208,6 +210,7 @@ impl UnixStream { target_os = "freebsd", target_os = "ios", target_os = "macos", + target_os = "netbsd", target_os = "openbsd" ))] pub fn peer_cred(&self) -> io::Result<UCred> { diff --git a/library/std/src/os/unix/process.rs b/library/std/src/os/unix/process.rs index 3dc389b7582..615290d2703 100644 --- a/library/std/src/os/unix/process.rs +++ b/library/std/src/os/unix/process.rs @@ -83,7 +83,7 @@ pub trait CommandExt: Sealed { /// /// When this closure is run, aspects such as the stdio file descriptors and /// working directory have successfully been changed, so output to these - /// locations may not appear where intended. + /// locations might not appear where intended. /// /// [POSIX fork() specification]: /// https://pubs.opengroup.org/onlinepubs/9699919799/functions/fork.html @@ -226,7 +226,7 @@ pub trait ExitStatusExt: Sealed { /// /// Panics on an attempt to make an `ExitStatusError` from a wait status of `0`. /// - /// Making an `ExitStatus` always succeds and never panics. + /// Making an `ExitStatus` always succeeds and never panics. #[stable(feature = "exit_status_from", since = "1.12.0")] fn from_raw(raw: i32) -> Self; diff --git a/library/std/src/os/unix/ucred.rs b/library/std/src/os/unix/ucred.rs index 1b4c18d3d84..32e6430d3f6 100644 --- a/library/std/src/os/unix/ucred.rs +++ b/library/std/src/os/unix/ucred.rs @@ -28,7 +28,12 @@ pub struct UCred { #[cfg(any(target_os = "android", target_os = "linux"))] pub use self::impl_linux::peer_cred; -#[cfg(any(target_os = "dragonfly", target_os = "freebsd", target_os = "openbsd"))] +#[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "openbsd", + target_os = "netbsd" +))] pub use self::impl_bsd::peer_cred; #[cfg(any(target_os = "macos", target_os = "ios",))] @@ -70,7 +75,12 @@ pub mod impl_linux { } } -#[cfg(any(target_os = "dragonfly", target_os = "freebsd", target_os = "openbsd"))] +#[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "openbsd", + target_os = "netbsd" +))] pub mod impl_bsd { use super::UCred; use crate::io; diff --git a/library/std/src/os/wasi/ffi.rs b/library/std/src/os/wasi/ffi.rs index f71f316d1ba..17e12a395a6 100644 --- a/library/std/src/os/wasi/ffi.rs +++ b/library/std/src/os/wasi/ffi.rs @@ -2,5 +2,8 @@ #![stable(feature = "rust1", since = "1.0.0")] +#[path = "../unix/ffi/os_str.rs"] +mod os_str; + #[stable(feature = "rust1", since = "1.0.0")] -pub use crate::sys_common::os_str_bytes::*; +pub use self::os_str::{OsStrExt, OsStringExt}; diff --git a/library/std/src/os/wasi/fs.rs b/library/std/src/os/wasi/fs.rs index ba4057bd34c..bd30d6ae3f3 100644 --- a/library/std/src/os/wasi/fs.rs +++ b/library/std/src/os/wasi/fs.rs @@ -1,7 +1,7 @@ //! WASI-specific extensions to primitives in the `std::fs` module. #![deny(unsafe_op_in_unsafe_fn)] -#![unstable(feature = "wasi_ext", issue = "none")] +#![unstable(feature = "wasi_ext", issue = "71213")] use crate::ffi::OsStr; use crate::fs::{self, File, Metadata, OpenOptions}; @@ -532,5 +532,6 @@ pub fn symlink_path<P: AsRef<Path>, U: AsRef<Path>>(old_path: P, new_path: U) -> } fn osstr2str(f: &OsStr) -> io::Result<&str> { - f.to_str().ok_or_else(|| io::Error::new_const(io::ErrorKind::Other, &"input must be utf-8")) + f.to_str() + .ok_or_else(|| io::Error::new_const(io::ErrorKind::Uncategorized, &"input must be utf-8")) } diff --git a/library/std/src/os/wasi/io.rs b/library/std/src/os/wasi/io.rs index b2e79cc1b4a..b6bc74da8e7 100644 --- a/library/std/src/os/wasi/io.rs +++ b/library/std/src/os/wasi/io.rs @@ -1,16 +1,23 @@ //! WASI-specific extensions to general I/O primitives #![deny(unsafe_op_in_unsafe_fn)] -#![unstable(feature = "wasi_ext", issue = "none")] +#![unstable(feature = "wasi_ext", issue = "71213")] use crate::fs; use crate::io; use crate::net; +use crate::os::raw; use crate::sys; use crate::sys_common::{AsInner, FromInner, IntoInner}; /// Raw file descriptors. -pub type RawFd = u32; +/// +/// This has type `c_int` to ease compatibility with code that also compiles on +/// Unix configurations, however unlike Unix and POSIX, in WASI negative file +/// descriptors are valid. Only `-1` is reserved for indicating errors. Code +/// intending to be portable across Unix platforms and WASI should avoid +/// assuming that negative file descriptors are invalid. +pub type RawFd = raw::c_int; /// A trait to extract the raw WASI file descriptor from an underlying /// object. @@ -161,41 +168,41 @@ impl IntoRawFd for fs::File { impl AsRawFd for io::Stdin { #[inline] fn as_raw_fd(&self) -> RawFd { - libc::STDIN_FILENO as RawFd + libc::STDIN_FILENO } } impl AsRawFd for io::Stdout { #[inline] fn as_raw_fd(&self) -> RawFd { - libc::STDOUT_FILENO as RawFd + libc::STDOUT_FILENO } } impl AsRawFd for io::Stderr { #[inline] fn as_raw_fd(&self) -> RawFd { - libc::STDERR_FILENO as RawFd + libc::STDERR_FILENO } } impl<'a> AsRawFd for io::StdinLock<'a> { #[inline] fn as_raw_fd(&self) -> RawFd { - libc::STDIN_FILENO as RawFd + libc::STDIN_FILENO } } impl<'a> AsRawFd for io::StdoutLock<'a> { #[inline] fn as_raw_fd(&self) -> RawFd { - libc::STDOUT_FILENO as RawFd + libc::STDOUT_FILENO } } impl<'a> AsRawFd for io::StderrLock<'a> { #[inline] fn as_raw_fd(&self) -> RawFd { - libc::STDERR_FILENO as RawFd + libc::STDERR_FILENO } } diff --git a/library/std/src/os/windows/process.rs b/library/std/src/os/windows/process.rs index 67756b15531..9e7ccd015b6 100644 --- a/library/std/src/os/windows/process.rs +++ b/library/std/src/os/windows/process.rs @@ -2,6 +2,7 @@ #![stable(feature = "process_extensions", since = "1.2.0")] +use crate::ffi::OsStr; use crate::os::windows::io::{AsRawHandle, FromRawHandle, IntoRawHandle, RawHandle}; use crate::process; use crate::sealed::Sealed; @@ -125,6 +126,13 @@ pub trait CommandExt: Sealed { /// [2]: <https://msdn.microsoft.com/en-us/library/17w5ykft.aspx> #[unstable(feature = "windows_process_extensions_force_quotes", issue = "82227")] fn force_quotes(&mut self, enabled: bool) -> &mut process::Command; + + /// Append literal text to the command line without any quoting or escaping. + /// + /// This is useful for passing arguments to `cmd.exe /c`, which doesn't follow + /// `CommandLineToArgvW` escaping rules. + #[unstable(feature = "windows_process_extensions_raw_arg", issue = "29494")] + fn raw_arg<S: AsRef<OsStr>>(&mut self, text_to_append_as_is: S) -> &mut process::Command; } #[stable(feature = "windows_process_extensions", since = "1.16.0")] @@ -138,4 +146,9 @@ impl CommandExt for process::Command { self.as_inner_mut().force_quotes(enabled); self } + + fn raw_arg<S: AsRef<OsStr>>(&mut self, raw_text: S) -> &mut process::Command { + self.as_inner_mut().raw_arg(raw_text.as_ref()); + self + } } diff --git a/library/std/src/panic.rs b/library/std/src/panic.rs index 9e3880dfd41..c1c03958497 100644 --- a/library/std/src/panic.rs +++ b/library/std/src/panic.rs @@ -3,24 +3,14 @@ #![stable(feature = "std_panic", since = "1.9.0")] use crate::any::Any; -use crate::cell::UnsafeCell; use crate::collections; -use crate::fmt; -use crate::future::Future; -use crate::ops::{Deref, DerefMut}; use crate::panicking; -use crate::pin::Pin; -use crate::ptr::{NonNull, Unique}; -use crate::rc::Rc; -use crate::stream::Stream; -use crate::sync::atomic; -use crate::sync::{Arc, Mutex, RwLock}; -use crate::task::{Context, Poll}; +use crate::sync::{Mutex, RwLock}; use crate::thread::Result; #[doc(hidden)] #[unstable(feature = "edition_panic", issue = "none", reason = "use panic!() instead")] -#[allow_internal_unstable(libstd_sys_internals)] +#[allow_internal_unstable(libstd_sys_internals, const_format_args)] #[cfg_attr(not(test), rustc_diagnostic_item = "std_panic_2015_macro")] #[rustc_macro_transparency = "semitransparent"] pub macro panic_2015 { @@ -31,7 +21,7 @@ pub macro panic_2015 { $crate::rt::begin_panic($msg) }), ($fmt:expr, $($arg:tt)+) => ({ - $crate::rt::begin_panic_fmt(&$crate::format_args!($fmt, $($arg)+)) + $crate::rt::begin_panic_fmt(&$crate::const_format_args!($fmt, $($arg)+)) }), } @@ -45,6 +35,9 @@ pub use crate::panicking::{set_hook, take_hook}; #[stable(feature = "panic_hooks", since = "1.10.0")] pub use core::panic::{Location, PanicInfo}; +#[stable(feature = "catch_unwind", since = "1.9.0")] +pub use core::panic::{AssertUnwindSafe, RefUnwindSafe, UnwindSafe}; + /// Panic the current thread with the given message as the panic payload. /// /// The message can be of any (`Any + Send`) type, not just strings. @@ -60,259 +53,16 @@ pub fn panic_any<M: 'static + Any + Send>(msg: M) -> ! { crate::panicking::begin_panic(msg); } -/// A marker trait which represents "panic safe" types in Rust. -/// -/// This trait is implemented by default for many types and behaves similarly in -/// terms of inference of implementation to the [`Send`] and [`Sync`] traits. The -/// purpose of this trait is to encode what types are safe to cross a [`catch_unwind`] -/// boundary with no fear of unwind safety. -/// -/// ## What is unwind safety? -/// -/// In Rust a function can "return" early if it either panics or calls a -/// function which transitively panics. This sort of control flow is not always -/// anticipated, and has the possibility of causing subtle bugs through a -/// combination of two critical components: -/// -/// 1. A data structure is in a temporarily invalid state when the thread -/// panics. -/// 2. This broken invariant is then later observed. -/// -/// Typically in Rust, it is difficult to perform step (2) because catching a -/// panic involves either spawning a thread (which in turns makes it difficult -/// to later witness broken invariants) or using the `catch_unwind` function in this -/// module. Additionally, even if an invariant is witnessed, it typically isn't a -/// problem in Rust because there are no uninitialized values (like in C or C++). -/// -/// It is possible, however, for **logical** invariants to be broken in Rust, -/// which can end up causing behavioral bugs. Another key aspect of unwind safety -/// in Rust is that, in the absence of `unsafe` code, a panic cannot lead to -/// memory unsafety. -/// -/// That was a bit of a whirlwind tour of unwind safety, but for more information -/// about unwind safety and how it applies to Rust, see an [associated RFC][rfc]. -/// -/// [rfc]: https://github.com/rust-lang/rfcs/blob/master/text/1236-stabilize-catch-panic.md -/// -/// ## What is `UnwindSafe`? -/// -/// Now that we've got an idea of what unwind safety is in Rust, it's also -/// important to understand what this trait represents. As mentioned above, one -/// way to witness broken invariants is through the `catch_unwind` function in this -/// module as it allows catching a panic and then re-using the environment of -/// the closure. -/// -/// Simply put, a type `T` implements `UnwindSafe` if it cannot easily allow -/// witnessing a broken invariant through the use of `catch_unwind` (catching a -/// panic). This trait is an auto trait, so it is automatically implemented for -/// many types, and it is also structurally composed (e.g., a struct is unwind -/// safe if all of its components are unwind safe). -/// -/// Note, however, that this is not an unsafe trait, so there is not a succinct -/// contract that this trait is providing. Instead it is intended as more of a -/// "speed bump" to alert users of `catch_unwind` that broken invariants may be -/// witnessed and may need to be accounted for. -/// -/// ## Who implements `UnwindSafe`? -/// -/// Types such as `&mut T` and `&RefCell<T>` are examples which are **not** -/// unwind safe. The general idea is that any mutable state which can be shared -/// across `catch_unwind` is not unwind safe by default. This is because it is very -/// easy to witness a broken invariant outside of `catch_unwind` as the data is -/// simply accessed as usual. -/// -/// Types like `&Mutex<T>`, however, are unwind safe because they implement -/// poisoning by default. They still allow witnessing a broken invariant, but -/// they already provide their own "speed bumps" to do so. -/// -/// ## When should `UnwindSafe` be used? -/// -/// It is not intended that most types or functions need to worry about this trait. -/// It is only used as a bound on the `catch_unwind` function and as mentioned -/// above, the lack of `unsafe` means it is mostly an advisory. The -/// [`AssertUnwindSafe`] wrapper struct can be used to force this trait to be -/// implemented for any closed over variables passed to `catch_unwind`. -#[stable(feature = "catch_unwind", since = "1.9.0")] -#[cfg_attr(all(not(bootstrap), not(test)), lang = "unwind_safe")] -#[rustc_on_unimplemented( - message = "the type `{Self}` may not be safely transferred across an unwind boundary", - label = "`{Self}` may not be safely transferred across an unwind boundary" -)] -pub auto trait UnwindSafe {} - -/// A marker trait representing types where a shared reference is considered -/// unwind safe. -/// -/// This trait is namely not implemented by [`UnsafeCell`], the root of all -/// interior mutability. -/// -/// This is a "helper marker trait" used to provide impl blocks for the -/// [`UnwindSafe`] trait, for more information see that documentation. -#[stable(feature = "catch_unwind", since = "1.9.0")] -#[cfg_attr(all(not(bootstrap), not(test)), lang = "ref_unwind_safe")] -#[rustc_on_unimplemented( - message = "the type `{Self}` may contain interior mutability and a reference may not be safely \ - transferrable across a catch_unwind boundary", - label = "`{Self}` may contain interior mutability and a reference may not be safely \ - transferrable across a catch_unwind boundary" -)] -pub auto trait RefUnwindSafe {} - -/// A simple wrapper around a type to assert that it is unwind safe. -/// -/// When using [`catch_unwind`] it may be the case that some of the closed over -/// variables are not unwind safe. For example if `&mut T` is captured the -/// compiler will generate a warning indicating that it is not unwind safe. It -/// may not be the case, however, that this is actually a problem due to the -/// specific usage of [`catch_unwind`] if unwind safety is specifically taken into -/// account. This wrapper struct is useful for a quick and lightweight -/// annotation that a variable is indeed unwind safe. -/// -/// # Examples -/// -/// One way to use `AssertUnwindSafe` is to assert that the entire closure -/// itself is unwind safe, bypassing all checks for all variables: -/// -/// ``` -/// use std::panic::{self, AssertUnwindSafe}; -/// -/// let mut variable = 4; -/// -/// // This code will not compile because the closure captures `&mut variable` -/// // which is not considered unwind safe by default. -/// -/// // panic::catch_unwind(|| { -/// // variable += 3; -/// // }); -/// -/// // This, however, will compile due to the `AssertUnwindSafe` wrapper -/// let result = panic::catch_unwind(AssertUnwindSafe(|| { -/// variable += 3; -/// })); -/// // ... -/// ``` -/// -/// Wrapping the entire closure amounts to a blanket assertion that all captured -/// variables are unwind safe. This has the downside that if new captures are -/// added in the future, they will also be considered unwind safe. Therefore, -/// you may prefer to just wrap individual captures, as shown below. This is -/// more annotation, but it ensures that if a new capture is added which is not -/// unwind safe, you will get a compilation error at that time, which will -/// allow you to consider whether that new capture in fact represent a bug or -/// not. -/// -/// ``` -/// use std::panic::{self, AssertUnwindSafe}; -/// -/// let mut variable = 4; -/// let other_capture = 3; -/// -/// let result = { -/// let mut wrapper = AssertUnwindSafe(&mut variable); -/// panic::catch_unwind(move || { -/// **wrapper += other_capture; -/// }) -/// }; -/// // ... -/// ``` -#[stable(feature = "catch_unwind", since = "1.9.0")] -pub struct AssertUnwindSafe<T>(#[stable(feature = "catch_unwind", since = "1.9.0")] pub T); - -// Implementations of the `UnwindSafe` trait: -// -// * By default everything is unwind safe -// * pointers T contains mutability of some form are not unwind safe -// * Unique, an owning pointer, lifts an implementation -// * Types like Mutex/RwLock which are explicitly poisoned are unwind safe -// * Our custom AssertUnwindSafe wrapper is indeed unwind safe - -#[stable(feature = "catch_unwind", since = "1.9.0")] -impl<T: ?Sized> !UnwindSafe for &mut T {} -#[stable(feature = "catch_unwind", since = "1.9.0")] -impl<T: RefUnwindSafe + ?Sized> UnwindSafe for &T {} -#[stable(feature = "catch_unwind", since = "1.9.0")] -impl<T: RefUnwindSafe + ?Sized> UnwindSafe for *const T {} -#[stable(feature = "catch_unwind", since = "1.9.0")] -impl<T: RefUnwindSafe + ?Sized> UnwindSafe for *mut T {} -#[unstable(feature = "ptr_internals", issue = "none")] -impl<T: UnwindSafe + ?Sized> UnwindSafe for Unique<T> {} -#[stable(feature = "nonnull", since = "1.25.0")] -impl<T: RefUnwindSafe + ?Sized> UnwindSafe for NonNull<T> {} #[stable(feature = "catch_unwind", since = "1.9.0")] impl<T: ?Sized> UnwindSafe for Mutex<T> {} #[stable(feature = "catch_unwind", since = "1.9.0")] impl<T: ?Sized> UnwindSafe for RwLock<T> {} -#[stable(feature = "catch_unwind", since = "1.9.0")] -impl<T> UnwindSafe for AssertUnwindSafe<T> {} - -// not covered via the Shared impl above b/c the inner contents use -// Cell/AtomicUsize, but the usage here is unwind safe so we can lift the -// impl up one level to Arc/Rc itself -#[stable(feature = "catch_unwind", since = "1.9.0")] -impl<T: RefUnwindSafe + ?Sized> UnwindSafe for Rc<T> {} -#[stable(feature = "catch_unwind", since = "1.9.0")] -impl<T: RefUnwindSafe + ?Sized> UnwindSafe for Arc<T> {} - -// Pretty simple implementations for the `RefUnwindSafe` marker trait, -// basically just saying that `UnsafeCell` is the -// only thing which doesn't implement it (which then transitively applies to -// everything else). -#[stable(feature = "catch_unwind", since = "1.9.0")] -impl<T: ?Sized> !RefUnwindSafe for UnsafeCell<T> {} -#[stable(feature = "catch_unwind", since = "1.9.0")] -impl<T> RefUnwindSafe for AssertUnwindSafe<T> {} #[stable(feature = "unwind_safe_lock_refs", since = "1.12.0")] impl<T: ?Sized> RefUnwindSafe for Mutex<T> {} #[stable(feature = "unwind_safe_lock_refs", since = "1.12.0")] impl<T: ?Sized> RefUnwindSafe for RwLock<T> {} -#[cfg(target_has_atomic_load_store = "ptr")] -#[stable(feature = "unwind_safe_atomic_refs", since = "1.14.0")] -impl RefUnwindSafe for atomic::AtomicIsize {} -#[cfg(target_has_atomic_load_store = "8")] -#[stable(feature = "integer_atomics_stable", since = "1.34.0")] -impl RefUnwindSafe for atomic::AtomicI8 {} -#[cfg(target_has_atomic_load_store = "16")] -#[stable(feature = "integer_atomics_stable", since = "1.34.0")] -impl RefUnwindSafe for atomic::AtomicI16 {} -#[cfg(target_has_atomic_load_store = "32")] -#[stable(feature = "integer_atomics_stable", since = "1.34.0")] -impl RefUnwindSafe for atomic::AtomicI32 {} -#[cfg(target_has_atomic_load_store = "64")] -#[stable(feature = "integer_atomics_stable", since = "1.34.0")] -impl RefUnwindSafe for atomic::AtomicI64 {} -#[cfg(target_has_atomic_load_store = "128")] -#[unstable(feature = "integer_atomics", issue = "32976")] -impl RefUnwindSafe for atomic::AtomicI128 {} - -#[cfg(target_has_atomic_load_store = "ptr")] -#[stable(feature = "unwind_safe_atomic_refs", since = "1.14.0")] -impl RefUnwindSafe for atomic::AtomicUsize {} -#[cfg(target_has_atomic_load_store = "8")] -#[stable(feature = "integer_atomics_stable", since = "1.34.0")] -impl RefUnwindSafe for atomic::AtomicU8 {} -#[cfg(target_has_atomic_load_store = "16")] -#[stable(feature = "integer_atomics_stable", since = "1.34.0")] -impl RefUnwindSafe for atomic::AtomicU16 {} -#[cfg(target_has_atomic_load_store = "32")] -#[stable(feature = "integer_atomics_stable", since = "1.34.0")] -impl RefUnwindSafe for atomic::AtomicU32 {} -#[cfg(target_has_atomic_load_store = "64")] -#[stable(feature = "integer_atomics_stable", since = "1.34.0")] -impl RefUnwindSafe for atomic::AtomicU64 {} -#[cfg(target_has_atomic_load_store = "128")] -#[unstable(feature = "integer_atomics", issue = "32976")] -impl RefUnwindSafe for atomic::AtomicU128 {} - -#[cfg(target_has_atomic_load_store = "8")] -#[stable(feature = "unwind_safe_atomic_refs", since = "1.14.0")] -impl RefUnwindSafe for atomic::AtomicBool {} - -#[cfg(target_has_atomic_load_store = "ptr")] -#[stable(feature = "unwind_safe_atomic_refs", since = "1.14.0")] -impl<T> RefUnwindSafe for atomic::AtomicPtr<T> {} - // https://github.com/rust-lang/rust/issues/62301 #[stable(feature = "hashbrown", since = "1.36.0")] impl<K, V, S> UnwindSafe for collections::HashMap<K, V, S> @@ -323,61 +73,6 @@ where { } -#[stable(feature = "catch_unwind", since = "1.9.0")] -impl<T> Deref for AssertUnwindSafe<T> { - type Target = T; - - fn deref(&self) -> &T { - &self.0 - } -} - -#[stable(feature = "catch_unwind", since = "1.9.0")] -impl<T> DerefMut for AssertUnwindSafe<T> { - fn deref_mut(&mut self) -> &mut T { - &mut self.0 - } -} - -#[stable(feature = "catch_unwind", since = "1.9.0")] -impl<R, F: FnOnce() -> R> FnOnce<()> for AssertUnwindSafe<F> { - type Output = R; - - extern "rust-call" fn call_once(self, _args: ()) -> R { - (self.0)() - } -} - -#[stable(feature = "std_debug", since = "1.16.0")] -impl<T: fmt::Debug> fmt::Debug for AssertUnwindSafe<T> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_tuple("AssertUnwindSafe").field(&self.0).finish() - } -} - -#[stable(feature = "futures_api", since = "1.36.0")] -impl<F: Future> Future for AssertUnwindSafe<F> { - type Output = F::Output; - - fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { - let pinned_field = unsafe { Pin::map_unchecked_mut(self, |x| &mut x.0) }; - F::poll(pinned_field, cx) - } -} - -#[unstable(feature = "async_stream", issue = "79024")] -impl<S: Stream> Stream for AssertUnwindSafe<S> { - type Item = S::Item; - - fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<S::Item>> { - unsafe { self.map_unchecked_mut(|x| &mut x.0) }.poll_next(cx) - } - - fn size_hint(&self) -> (usize, Option<usize>) { - self.0.size_hint() - } -} - /// 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 @@ -406,7 +101,7 @@ impl<S: Stream> Stream for AssertUnwindSafe<S> { /// /// # Notes /// -/// Note that this function **may not catch all panics** in Rust. A panic in +/// Note that this function **might not catch all panics** in Rust. A panic in /// Rust 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. diff --git a/library/std/src/panicking.rs b/library/std/src/panicking.rs index 02957e75a74..7de70091bec 100644 --- a/library/std/src/panicking.rs +++ b/library/std/src/panicking.rs @@ -19,7 +19,7 @@ use crate::process; use crate::sync::atomic::{AtomicBool, Ordering}; use crate::sys::stdio::panic_output; use crate::sys_common::backtrace::{self, RustBacktrace}; -use crate::sys_common::rwlock::RWLock; +use crate::sys_common::rwlock::StaticRWLock; use crate::sys_common::thread_info; use crate::thread; @@ -43,11 +43,13 @@ use realstd::io::set_output_capture; #[allow(improper_ctypes)] extern "C" { fn __rust_panic_cleanup(payload: *mut u8) -> *mut (dyn Any + Send + 'static); +} +#[allow(improper_ctypes)] +extern "C-unwind" { /// `payload` is passed through another layer of raw pointers as `&mut dyn Trait` is not /// FFI-safe. `BoxMeUp` lazily performs allocation only when needed (this avoids allocations /// when using the "abort" panic runtime). - #[unwind(allowed)] fn __rust_start_panic(payload: *mut &mut dyn BoxMeUp) -> u32; } @@ -74,7 +76,7 @@ enum Hook { Custom(*mut (dyn Fn(&PanicInfo<'_>) + 'static + Sync + Send)), } -static HOOK_LOCK: RWLock = RWLock::new(); +static HOOK_LOCK: StaticRWLock = StaticRWLock::new(); static mut HOOK: Hook = Hook::Default; /// Registers a custom panic hook, replacing any that was previously registered. @@ -117,10 +119,10 @@ pub fn set_hook(hook: Box<dyn Fn(&PanicInfo<'_>) + 'static + Sync + Send>) { } unsafe { - HOOK_LOCK.write(); + let guard = HOOK_LOCK.write(); let old_hook = HOOK; HOOK = Hook::Custom(Box::into_raw(hook)); - HOOK_LOCK.write_unlock(); + drop(guard); if let Hook::Custom(ptr) = old_hook { #[allow(unused_must_use)] @@ -165,10 +167,10 @@ pub fn take_hook() -> Box<dyn Fn(&PanicInfo<'_>) + 'static + Sync + Send> { } unsafe { - HOOK_LOCK.write(); + let guard = HOOK_LOCK.write(); let hook = HOOK; HOOK = Hook::Default; - HOOK_LOCK.write_unlock(); + drop(guard); match hook { Hook::Default => Box::new(default_hook), @@ -193,7 +195,7 @@ fn default_hook(info: &PanicInfo<'_>) { Some(s) => *s, None => match info.payload().downcast_ref::<String>() { Some(s) => &s[..], - None => "Box<Any>", + None => "Box<dyn Any>", }, }; let thread = thread_info::current_thread(); @@ -448,6 +450,7 @@ pub fn panicking() -> bool { #[cfg_attr(not(feature = "panic_immediate_abort"), track_caller)] #[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))] #[cfg_attr(feature = "panic_immediate_abort", inline)] +#[cfg_attr(all(not(bootstrap), not(test)), lang = "begin_panic_fmt")] pub fn begin_panic_fmt(msg: &fmt::Arguments<'_>) -> ! { if cfg!(feature = "panic_immediate_abort") { intrinsics::abort() @@ -459,7 +462,6 @@ pub fn begin_panic_fmt(msg: &fmt::Arguments<'_>) -> ! { /// Entry point of panics from the libcore crate (`panic_impl` lang item). #[cfg_attr(not(test), panic_handler)] -#[unwind(allowed)] pub fn begin_panic_handler(info: &PanicInfo<'_>) -> ! { struct PanicPayload<'a> { inner: &'a fmt::Arguments<'a>, @@ -608,7 +610,7 @@ fn rust_panic_with_hook( unsafe { let mut info = PanicInfo::internal_constructor(message, location); - HOOK_LOCK.read(); + let _guard = HOOK_LOCK.read(); match HOOK { // 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 @@ -626,7 +628,6 @@ fn rust_panic_with_hook( (*ptr)(&info); } }; - HOOK_LOCK.read_unlock(); } if panics > 1 { diff --git a/library/std/src/path.rs b/library/std/src/path.rs index ede147aca12..69419145b1b 100644 --- a/library/std/src/path.rs +++ b/library/std/src/path.rs @@ -951,7 +951,7 @@ impl FusedIterator for Components<'_> {} impl<'a> cmp::PartialEq for Components<'a> { #[inline] fn eq(&self, other: &Components<'a>) -> bool { - Iterator::eq(self.clone(), other.clone()) + Iterator::eq(self.clone().rev(), other.clone().rev()) } } @@ -1398,7 +1398,7 @@ impl PathBuf { /// Invokes [`shrink_to`] on the underlying instance of [`OsString`]. /// /// [`shrink_to`]: OsString::shrink_to - #[unstable(feature = "shrink_to", issue = "56431")] + #[stable(feature = "shrink_to", since = "1.56.0")] #[inline] pub fn shrink_to(&mut self, min_capacity: usize) { self.inner.shrink_to(min_capacity) @@ -2592,6 +2592,32 @@ impl Path { fs::metadata(self).map(|m| m.is_dir()).unwrap_or(false) } + /// Returns true if the path exists on disk and is pointing at a symbolic link. + /// + /// This function will not traverse symbolic links. + /// In case of a broken symbolic link this will also return true. + /// + /// If you cannot access the directory containing the file, e.g., because of a + /// permission error, this will return false. + /// + /// # Examples + /// + #[cfg_attr(unix, doc = "```no_run")] + #[cfg_attr(not(unix), doc = "```ignore")] + /// #![feature(is_symlink)] + /// use std::path::Path; + /// use std::os::unix::fs::symlink; + /// + /// let link_path = Path::new("link"); + /// symlink("/origin_does_not_exists/", link_path).unwrap(); + /// assert_eq!(link_path.is_symlink(), true); + /// assert_eq!(link_path.exists(), false); + /// ``` + #[unstable(feature = "is_symlink", issue = "85748")] + pub fn is_symlink(&self) -> bool { + fs::symlink_metadata(self).map(|m| m.is_symlink()).unwrap_or(false) + } + /// Converts a [`Box<Path>`](Box) into a [`PathBuf`] without copying or /// allocating. #[stable(feature = "into_boxed_path", since = "1.20.0")] diff --git a/library/std/src/prelude/mod.rs b/library/std/src/prelude/mod.rs index 12d52cc8e0b..d4bf6aeefee 100644 --- a/library/std/src/prelude/mod.rs +++ b/library/std/src/prelude/mod.rs @@ -25,8 +25,10 @@ //! //! # Prelude contents //! -//! The current version of the prelude (version 1) lives in -//! [`std::prelude::v1`], and re-exports the following: +//! The first version of the prelude is used in Rust 2015 and Rust 2018, +//! and lives in [`std::prelude::v1`]. +//! [`std::prelude::rust_2015`] and [`std::prelude::rust_2018`] re-export this prelude. +//! It re-exports the following: //! //! * <code>[std::marker]::{[Copy], [Send], [Sized], [Sync], [Unpin]}</code>, //! marker traits that indicate fundamental properties of types. @@ -58,6 +60,12 @@ //! * <code>[std::string]::{[String], [ToString]}</code>, heap-allocated strings. //! * <code>[std::vec]::[Vec]</code>, a growable, heap-allocated vector. //! +//! The prelude used in Rust 2021, [`std::prelude::rust_2021`], includes all of the above, +//! and in addition re-exports: +//! +//! * <code>[std::convert]::{[TryFrom], [TryInto]}</code>, +//! * <code>[std::iter]::[FromIterator]</code>. +//! //! [mem::drop]: crate::mem::drop //! [std::borrow]: crate::borrow //! [std::boxed]: crate::boxed @@ -71,10 +79,16 @@ //! [std::ops]: crate::ops //! [std::option]: crate::option //! [`std::prelude::v1`]: v1 +//! [`std::prelude::rust_2015`]: rust_2015 +//! [`std::prelude::rust_2018`]: rust_2018 +//! [`std::prelude::rust_2021`]: rust_2021 //! [std::result]: crate::result //! [std::slice]: crate::slice //! [std::string]: crate::string //! [std::vec]: mod@crate::vec +//! [TryFrom]: crate::convert::TryFrom +//! [TryInto]: crate::convert::TryInto +//! [FromIterator]: crate::iter::FromIterator //! [`to_owned`]: crate::borrow::ToOwned::to_owned //! [book-closures]: ../../book/ch13-01-closures.html //! [book-dtor]: ../../book/ch15-03-drop.html @@ -88,9 +102,9 @@ pub mod v1; /// The 2015 version of the prelude of The Rust Standard Library. /// /// See the [module-level documentation](self) for more. -#[unstable(feature = "prelude_2015", issue = "85684")] +#[stable(feature = "prelude_2015", since = "1.55.0")] pub mod rust_2015 { - #[unstable(feature = "prelude_2015", issue = "85684")] + #[stable(feature = "prelude_2015", since = "1.55.0")] #[doc(no_inline)] pub use super::v1::*; } @@ -98,9 +112,9 @@ pub mod rust_2015 { /// The 2018 version of the prelude of The Rust Standard Library. /// /// See the [module-level documentation](self) for more. -#[unstable(feature = "prelude_2018", issue = "85684")] +#[stable(feature = "prelude_2018", since = "1.55.0")] pub mod rust_2018 { - #[unstable(feature = "prelude_2018", issue = "85684")] + #[stable(feature = "prelude_2018", since = "1.55.0")] #[doc(no_inline)] pub use super::v1::*; } @@ -108,13 +122,13 @@ pub mod rust_2018 { /// The 2021 version of the prelude of The Rust Standard Library. /// /// See the [module-level documentation](self) for more. -#[unstable(feature = "prelude_2021", issue = "85684")] +#[stable(feature = "prelude_2021", since = "1.55.0")] pub mod rust_2021 { - #[unstable(feature = "prelude_2021", issue = "85684")] + #[stable(feature = "prelude_2021", since = "1.55.0")] #[doc(no_inline)] pub use super::v1::*; - #[unstable(feature = "prelude_2021", issue = "85684")] + #[stable(feature = "prelude_2021", since = "1.55.0")] #[doc(no_inline)] pub use core::prelude::rust_2021::*; } diff --git a/library/std/src/prelude/v1.rs b/library/std/src/prelude/v1.rs index 4a3c3ba1635..772044f0149 100644 --- a/library/std/src/prelude/v1.rs +++ b/library/std/src/prelude/v1.rs @@ -39,12 +39,28 @@ pub use crate::result::Result::{self, Err, Ok}; #[allow(deprecated)] #[doc(no_inline)] pub use core::prelude::v1::{ - asm, assert, cfg, column, compile_error, concat, concat_idents, env, file, format_args, - format_args_nl, global_asm, include, include_bytes, include_str, line, llvm_asm, log_syntax, - module_path, option_env, stringify, trace_macros, Clone, Copy, Debug, Default, Eq, Hash, Ord, - PartialEq, PartialOrd, + assert, cfg, column, compile_error, concat, concat_idents, env, file, format_args, + format_args_nl, include, include_bytes, include_str, line, llvm_asm, log_syntax, module_path, + option_env, stringify, trace_macros, Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, + PartialOrd, }; +#[unstable( + feature = "asm", + issue = "72016", + reason = "inline assembly is not stable enough for use and is subject to change" +)] +#[doc(no_inline)] +pub use core::prelude::v1::asm; + +#[unstable( + feature = "global_asm", + issue = "35119", + reason = "`global_asm!` is not stable enough for use and is subject to change" +)] +#[doc(no_inline)] +pub use core::prelude::v1::global_asm; + // FIXME: Attribute and internal derive macros are not documented because for them rustdoc generates // dead links which fail link checker testing. #[stable(feature = "builtin_macro_prelude", since = "1.38.0")] diff --git a/library/std/src/primitive_docs.rs b/library/std/src/primitive_docs.rs index 8a3e425350a..dc4572cd936 100644 --- a/library/std/src/primitive_docs.rs +++ b/library/std/src/primitive_docs.rs @@ -277,8 +277,8 @@ mod prim_never {} /// scalar value]', which is similar to, but not the same as, a '[Unicode code /// point]'. /// -/// [Unicode scalar value]: http://www.unicode.org/glossary/#unicode_scalar_value -/// [Unicode code point]: http://www.unicode.org/glossary/#code_point +/// [Unicode scalar value]: https://www.unicode.org/glossary/#unicode_scalar_value +/// [Unicode code point]: https://www.unicode.org/glossary/#code_point /// /// This documentation describes a number of methods and trait implementations on the /// `char` type. For technical reasons, there is additional, separate @@ -303,7 +303,7 @@ mod prim_never {} /// /// [`String`]: string/struct.String.html /// -/// As always, remember that a human intuition for 'character' may not map to +/// As always, remember that a human intuition for 'character' might not map to /// Unicode's definitions. For example, despite looking similar, the 'é' /// character is one Unicode code point while 'é' is two Unicode code points: /// diff --git a/library/std/src/process.rs b/library/std/src/process.rs index 6903ba90560..f5ce5210f81 100644 --- a/library/std/src/process.rs +++ b/library/std/src/process.rs @@ -166,7 +166,7 @@ use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner}; /// [`wait`]: Child::wait #[stable(feature = "process", since = "1.0.0")] pub struct Child { - handle: imp::Process, + pub(crate) handle: imp::Process, /// The handle for writing to the child's standard input (stdin), if it has /// been captured. To avoid partially moving @@ -205,6 +205,10 @@ pub struct Child { pub stderr: Option<ChildStderr>, } +/// Allows extension traits within `std`. +#[unstable(feature = "sealed", issue = "none")] +impl crate::sealed::Sealed for Child {} + impl AsInner<imp::Process> for Child { fn as_inner(&self) -> &imp::Process { &self.handle @@ -452,7 +456,7 @@ impl fmt::Debug for ChildStderr { /// /// let output = if cfg!(target_os = "windows") { /// Command::new("cmd") -/// .args(&["/C", "echo hello"]) +/// .args(["/C", "echo hello"]) /// .output() /// .expect("failed to execute process") /// } else { @@ -609,7 +613,7 @@ impl Command { /// use std::process::Command; /// /// Command::new("ls") - /// .args(&["-l", "-a"]) + /// .args(["-l", "-a"]) /// .spawn() /// .expect("ls command failed to start"); /// ``` @@ -1453,7 +1457,7 @@ impl ExitStatus { /// /// In Unix terms the return value is the **exit status**: the value passed to `exit`, if the /// process finished by calling `exit`. Note that on Unix the exit status is truncated to 8 - /// bits, and that values that didn't come from a program's call to `exit` may be invented the + /// bits, and that values that didn't come from a program's call to `exit` may be invented by the /// runtime system (often, for example, 255, 254, 127 or 126). /// /// On Unix, this will return `None` if the process was terminated by a signal. @@ -1568,7 +1572,7 @@ impl ExitStatusError { /// Reports the exit code, if applicable, from an `ExitStatusError`, as a `NonZero` /// - /// This is exaclty like [`code()`](Self::code), except that it returns a `NonZeroI32`. + /// This is exactly like [`code()`](Self::code), except that it returns a `NonZeroI32`. /// /// Plain `code`, returning a plain integer, is provided because is is often more convenient. /// The returned value from `code()` is indeed also nonzero; use `code_nonzero()` when you want @@ -1658,8 +1662,7 @@ impl Child { /// Forces the child process to exit. If the child has already exited, an [`InvalidInput`] /// error is returned. /// - /// The mapping to [`ErrorKind`]s is not part of the compatibility contract of the function, - /// especially the [`Other`] kind might change to more specific kinds in the future. + /// The mapping to [`ErrorKind`]s is not part of the compatibility contract of the function. /// /// This is equivalent to sending a SIGKILL on Unix platforms. /// @@ -1680,7 +1683,6 @@ impl Child { /// /// [`ErrorKind`]: io::ErrorKind /// [`InvalidInput`]: io::ErrorKind::InvalidInput - /// [`Other`]: io::ErrorKind::Other #[stable(feature = "process", since = "1.0.0")] pub fn kill(&mut self) -> io::Result<()> { self.handle.kill() @@ -1900,6 +1902,9 @@ pub fn exit(code: i32) -> ! { /// process, no destructors on the current stack or any other thread's stack /// will be run. /// +/// Rust IO buffers (eg, from `BufWriter`) will not be flushed. +/// Likewise, C stdio buffers will (on most platforms) not be flushed. +/// /// This is in contrast to the default behaviour of [`panic!`] which unwinds /// the current thread's stack and calls all destructors. /// When `panic="abort"` is set, either as an argument to `rustc` or in a @@ -1910,6 +1915,10 @@ pub fn exit(code: i32) -> ! { /// this function at a known point where there are no more destructors left /// to run. /// +/// The process's termination will be similar to that from the C `abort()` +/// function. On Unix, the process will terminate with signal `SIGABRT`, which +/// typically means that the shell prints "Aborted". +/// /// # Examples /// /// ```no_run diff --git a/library/std/src/process/tests.rs b/library/std/src/process/tests.rs index 05e093434be..bc71c150550 100644 --- a/library/std/src/process/tests.rs +++ b/library/std/src/process/tests.rs @@ -399,3 +399,12 @@ fn test_command_implements_send_sync() { fn take_send_sync_type<T: Send + Sync>(_: T) {} take_send_sync_type(Command::new("")) } + +// Ensure that starting a process with no environment variables works on Windows. +// This will fail if the environment block is ill-formed. +#[test] +#[cfg(windows)] +fn env_empty() { + let p = Command::new("cmd").args(&["/C", "exit 0"]).env_clear().spawn(); + assert!(p.is_ok()); +} diff --git a/library/std/src/rt.rs b/library/std/src/rt.rs index 1e19aff51f8..72e6c23ee49 100644 --- a/library/std/src/rt.rs +++ b/library/std/src/rt.rs @@ -24,18 +24,32 @@ fn lang_start_internal( main: &(dyn Fn() -> i32 + Sync + crate::panic::RefUnwindSafe), argc: isize, argv: *const *const u8, -) -> isize { - use crate::panic; - use crate::sys_common; - +) -> Result<isize, !> { + use crate::{mem, panic, sys, sys_common}; + let rt_abort = move |e| { + mem::forget(e); + rtabort!("initialization or cleanup bug"); + }; + // Guard against the code called by this function from unwinding outside of the Rust-controlled + // code, which is UB. This is a requirement imposed by a combination of how the + // `#[lang="start"]` attribute is implemented as well as by the implementation of the panicking + // mechanism itself. + // + // There are a couple of instances where unwinding can begin. First is inside of the + // `rt::init`, `rt::cleanup` and similar functions controlled by libstd. In those instances a + // panic is a libstd implementation bug. A quite likely one too, as there isn't any way to + // prevent libstd from accidentally introducing a panic to these functions. Another is from + // user code from `main` or, more nefariously, as described in e.g. issue #86030. // SAFETY: Only called once during runtime initialization. - unsafe { sys_common::rt::init(argc, argv) }; - - let exit_code = panic::catch_unwind(main); - - sys_common::rt::cleanup(); - - exit_code.unwrap_or(101) as isize + panic::catch_unwind(move || unsafe { sys_common::rt::init(argc, argv) }).map_err(rt_abort)?; + let ret_code = panic::catch_unwind(move || panic::catch_unwind(main).unwrap_or(101) as isize) + .map_err(move |e| { + mem::forget(e); + rtprintpanic!("drop of the panic payload panicked"); + sys::abort_internal() + }); + panic::catch_unwind(sys_common::rt::cleanup).map_err(rt_abort)?; + ret_code } #[cfg(not(test))] @@ -50,4 +64,5 @@ fn lang_start<T: crate::process::Termination + 'static>( argc, argv, ) + .into_ok() } diff --git a/library/std/src/sync/condvar.rs b/library/std/src/sync/condvar.rs index 2f0b32c90d0..00a4afc5705 100644 --- a/library/std/src/sync/condvar.rs +++ b/library/std/src/sync/condvar.rs @@ -254,7 +254,7 @@ impl Condvar { /// except that the thread will be blocked for roughly no longer /// than `ms` milliseconds. This method should not be used for /// precise timing due to anomalies such as preemption or platform - /// differences that may not cause the maximum amount of time + /// differences that might not cause the maximum amount of time /// waited to be precisely `ms`. /// /// Note that the best effort is made to ensure that the time waited is @@ -317,7 +317,7 @@ impl Condvar { /// The semantics of this function are equivalent to [`wait`] except that /// the thread will be blocked for roughly no longer than `dur`. This /// method should not be used for precise timing due to anomalies such as - /// preemption or platform differences that may not cause the maximum + /// preemption or platform differences that might not cause the maximum /// amount of time waited to be precisely `dur`. /// /// Note that the best effort is made to ensure that the time waited is @@ -392,7 +392,7 @@ impl Condvar { /// The semantics of this function are equivalent to [`wait_while`] except /// that the thread will be blocked for roughly no longer than `dur`. This /// method should not be used for precise timing due to anomalies such as - /// preemption or platform differences that may not cause the maximum + /// preemption or platform differences that might not cause the maximum /// amount of time waited to be precisely `dur`. /// /// Note that the best effort is made to ensure that the time waited is diff --git a/library/std/src/sync/mpsc/mod.rs b/library/std/src/sync/mpsc/mod.rs index ea1d598d264..b4f4456537b 100644 --- a/library/std/src/sync/mpsc/mod.rs +++ b/library/std/src/sync/mpsc/mod.rs @@ -105,6 +105,35 @@ //! }); //! rx.recv().unwrap(); //! ``` +//! +//! Unbounded receive loop: +//! +//! ``` +//! use std::sync::mpsc::sync_channel; +//! use std::thread; +//! +//! let (tx, rx) = sync_channel(3); +//! +//! for _ in 0..3 { +//! // It would be the same without thread and clone here +//! // since there will still be one `tx` left. +//! let tx = tx.clone(); +//! // cloned tx dropped within thread +//! thread::spawn(move || tx.send("ok").unwrap()); +//! } +//! +//! // Drop the last sender to stop `rx` waiting for message. +//! // The program will not complete if we comment this out. +//! // **All** `tx` needs to be dropped for `rx` to have `Err`. +//! drop(tx); +//! +//! // Unbounded receiver waiting for all senders to complete. +//! while let Ok(msg) = rx.recv() { +//! println!("{}", msg); +//! } +//! +//! println!("completed"); +//! ``` #![stable(feature = "rust1", since = "1.0.0")] @@ -437,6 +466,9 @@ pub struct IntoIter<T> { /// /// Messages can be sent through this channel with [`send`]. /// +/// Note: all senders (the original and the clones) need to be dropped for the receiver +/// to stop blocking to receive messages with [`Receiver::recv`]. +/// /// [`send`]: Sender::send /// /// # Examples @@ -643,7 +675,7 @@ impl<T> UnsafeFlavor<T> for Receiver<T> { /// the same order as it was sent, and no [`send`] will block the calling thread /// (this channel has an "infinite buffer", unlike [`sync_channel`], which will /// block after its buffer limit is reached). [`recv`] will block until a message -/// is available. +/// is available while there is at least one [`Sender`] alive (including clones). /// /// The [`Sender`] can be cloned to [`send`] to the same channel multiple times, but /// only one [`Receiver`] is supported. @@ -806,6 +838,11 @@ impl<T> Sender<T> { #[stable(feature = "rust1", since = "1.0.0")] impl<T> Clone for Sender<T> { + /// Clone a sender to send to other threads. + /// + /// Note, be aware of the lifetime of the sender because all senders + /// (including the original) need to be dropped in order for + /// [`Receiver::recv`] to stop blocking. fn clone(&self) -> Sender<T> { let packet = match *unsafe { self.inner() } { Flavor::Oneshot(ref p) => { @@ -1064,9 +1101,10 @@ impl<T> Receiver<T> { /// corresponding channel has hung up. /// /// This function will always block the current thread if there is no data - /// available and it's possible for more data to be sent. Once a message is - /// sent to the corresponding [`Sender`] (or [`SyncSender`]), then this - /// receiver will wake up and return that message. + /// available and it's possible for more data to be sent (at least one sender + /// still exists). Once a message is sent to the corresponding [`Sender`] + /// (or [`SyncSender`]), this receiver will wake up and return that + /// message. /// /// If the corresponding [`Sender`] has disconnected, or it disconnects while /// this call is blocking, this call will wake up and return [`Err`] to @@ -1146,9 +1184,10 @@ impl<T> Receiver<T> { /// corresponding channel has hung up, or if it waits more than `timeout`. /// /// This function will always block the current thread if there is no data - /// available and it's possible for more data to be sent. Once a message is - /// sent to the corresponding [`Sender`] (or [`SyncSender`]), then this - /// receiver will wake up and return that message. + /// available and it's possible for more data to be sent (at least one sender + /// still exists). Once a message is sent to the corresponding [`Sender`] + /// (or [`SyncSender`]), this receiver will wake up and return that + /// message. /// /// If the corresponding [`Sender`] has disconnected, or it disconnects while /// this call is blocking, this call will wake up and return [`Err`] to diff --git a/library/std/src/sync/mpsc/mpsc_queue.rs b/library/std/src/sync/mpsc/mpsc_queue.rs index 42bc639dc25..cdd64a5def5 100644 --- a/library/std/src/sync/mpsc/mpsc_queue.rs +++ b/library/std/src/sync/mpsc/mpsc_queue.rs @@ -6,10 +6,10 @@ //! //! Note that the current implementation of this queue has a caveat of the `pop` //! method, and see the method for more information about it. Due to this -//! caveat, this queue may not be appropriate for all use-cases. +//! caveat, this queue might not be appropriate for all use-cases. -// http://www.1024cores.net/home/lock-free-algorithms -// /queues/non-intrusive-mpsc-node-based-queue +// https://www.1024cores.net/home/lock-free-algorithms +// /queues/non-intrusive-mpsc-node-based-queue #[cfg(all(test, not(target_os = "emscripten")))] mod tests; diff --git a/library/std/src/sync/mpsc/spsc_queue.rs b/library/std/src/sync/mpsc/spsc_queue.rs index 9bf99f193ca..7e745eb31de 100644 --- a/library/std/src/sync/mpsc/spsc_queue.rs +++ b/library/std/src/sync/mpsc/spsc_queue.rs @@ -4,7 +4,7 @@ //! concurrently between two threads. This data structure is safe to use and //! enforces the semantics that there is one pusher and one popper. -// http://www.1024cores.net/home/lock-free-algorithms/queues/unbounded-spsc-queue +// https://www.1024cores.net/home/lock-free-algorithms/queues/unbounded-spsc-queue #[cfg(all(test, not(target_os = "emscripten")))] mod tests; diff --git a/library/std/src/sync/mpsc/stream.rs b/library/std/src/sync/mpsc/stream.rs index a652f24c58a..2a1d3f8967e 100644 --- a/library/std/src/sync/mpsc/stream.rs +++ b/library/std/src/sync/mpsc/stream.rs @@ -339,7 +339,7 @@ impl<T> Packet<T> { // At this point in time, we have gated all future senders from sending, // and we have flagged the channel as being disconnected. The senders - // still have some responsibility, however, because some sends may not + // still have some responsibility, however, because some sends might not // complete until after we flag the disconnection. There are more // details in the sending methods that see DISCONNECTED } @@ -370,7 +370,7 @@ impl<T> Packet<T> { // at all. // // Hence, because of these invariants, we immediately return `Ok(true)`. - // Note that the data may not actually be sent on the channel just yet. + // Note that the data might not actually be sent on the channel just yet. // The other end could have flagged the upgrade but not sent data to // this end. This is fine because we know it's a small bounded windows // of time until the data is actually sent. diff --git a/library/std/src/sync/mutex.rs b/library/std/src/sync/mutex.rs index e7c5479ab9b..e1d6324c17e 100644 --- a/library/std/src/sync/mutex.rs +++ b/library/std/src/sync/mutex.rs @@ -217,26 +217,6 @@ impl<T> Mutex<T> { data: UnsafeCell::new(t), } } - - /// Immediately drops the guard, and consequently unlocks the mutex. - /// - /// This function is equivalent to calling [`drop`] on the guard but is more self-documenting. - /// Alternately, the guard will be automatically dropped when it goes out of scope. - /// - /// ``` - /// #![feature(mutex_unlock)] - /// - /// use std::sync::Mutex; - /// let mutex = Mutex::new(0); - /// - /// let mut guard = mutex.lock().unwrap(); - /// *guard += 20; - /// Mutex::unlock(guard); - /// ``` - #[unstable(feature = "mutex_unlock", issue = "81872")] - pub fn unlock(guard: MutexGuard<'_, T>) { - drop(guard); - } } impl<T: ?Sized> Mutex<T> { @@ -333,6 +313,26 @@ impl<T: ?Sized> Mutex<T> { } } + /// Immediately drops the guard, and consequently unlocks the mutex. + /// + /// This function is equivalent to calling [`drop`] on the guard but is more self-documenting. + /// Alternately, the guard will be automatically dropped when it goes out of scope. + /// + /// ``` + /// #![feature(mutex_unlock)] + /// + /// use std::sync::Mutex; + /// let mutex = Mutex::new(0); + /// + /// let mut guard = mutex.lock().unwrap(); + /// *guard += 20; + /// Mutex::unlock(guard); + /// ``` + #[unstable(feature = "mutex_unlock", issue = "81872")] + pub fn unlock(guard: MutexGuard<'_, T>) { + drop(guard); + } + /// Determines whether the mutex is poisoned. /// /// If another thread is active, the mutex can still become poisoned at any diff --git a/library/std/src/sync/once.rs b/library/std/src/sync/once.rs index 6da6c18e477..a2e935a0ceb 100644 --- a/library/std/src/sync/once.rs +++ b/library/std/src/sync/once.rs @@ -198,7 +198,7 @@ impl Once { /// routine is currently running. /// /// When this function returns, it is guaranteed that some initialization - /// has run and completed (it may not be the closure specified). It is also + /// has run and completed (it might not be the closure specified). It is also /// guaranteed that any memory writes performed by the executed closure can /// be reliably observed by other threads at this point (there is a /// happens-before relation between the closure and code executing after the diff --git a/library/std/src/sync/poison.rs b/library/std/src/sync/poison.rs index 05e1833c3e5..fa950331e64 100644 --- a/library/std/src/sync/poison.rs +++ b/library/std/src/sync/poison.rs @@ -120,7 +120,7 @@ pub type LockResult<Guard> = Result<Guard, PoisonError<Guard>>; /// A type alias for the result of a nonblocking locking method. /// /// For more information, see [`LockResult`]. A `TryLockResult` doesn't -/// necessarily hold the associated guard in the [`Err`] type as the lock may not +/// necessarily hold the associated guard in the [`Err`] type as the lock might not /// have been acquired for other reasons. #[stable(feature = "rust1", since = "1.0.0")] pub type TryLockResult<Guard> = Result<Guard, TryLockError<Guard>>; diff --git a/library/std/src/sync/rwlock.rs b/library/std/src/sync/rwlock.rs index 9d521ab14cb..e50d62d8173 100644 --- a/library/std/src/sync/rwlock.rs +++ b/library/std/src/sync/rwlock.rs @@ -3,9 +3,7 @@ mod tests; use crate::cell::UnsafeCell; use crate::fmt; -use crate::mem; use crate::ops::{Deref, DerefMut}; -use crate::ptr; use crate::sync::{poison, LockResult, TryLockError, TryLockResult}; use crate::sys_common::rwlock as sys; @@ -25,7 +23,19 @@ use crate::sys_common::rwlock as sys; /// system's implementation, and this type does not guarantee that any /// particular policy will be used. In particular, a writer which is waiting to /// acquire the lock in `write` might or might not block concurrent calls to -/// `read`. +/// `read`, e.g.: +/// +/// <details><summary>Potential deadlock example</summary> +/// +/// ```text +/// // Thread 1 | // Thread 2 +/// let _rg = lock.read(); | +/// | // will block +/// | let _wg = lock.write(); +/// // may deadlock | +/// let _rg = lock.read(); | +/// ``` +/// </details> /// /// The type parameter `T` represents the data that this lock protects. It is /// required that `T` satisfies [`Send`] to be shared across threads and @@ -66,7 +76,7 @@ use crate::sys_common::rwlock as sys; /// [`Mutex`]: super::Mutex #[stable(feature = "rust1", since = "1.0.0")] pub struct RwLock<T: ?Sized> { - inner: Box<sys::RWLock>, + inner: sys::MovableRWLock, poison: poison::Flag, data: UnsafeCell<T>, } @@ -130,7 +140,7 @@ impl<T> RwLock<T> { #[stable(feature = "rust1", since = "1.0.0")] pub fn new(t: T) -> RwLock<T> { RwLock { - inner: box sys::RWLock::new(), + inner: sys::MovableRWLock::new(), poison: poison::Flag::new(), data: UnsafeCell::new(t), } @@ -376,24 +386,8 @@ impl<T: ?Sized> RwLock<T> { where T: Sized, { - // We know statically that there are no outstanding references to - // `self` so there's no need to lock the inner lock. - // - // To get the inner value, we'd like to call `data.into_inner()`, - // but because `RwLock` impl-s `Drop`, we can't move out of it, so - // we'll have to destructure it manually instead. - unsafe { - // Like `let RwLock { inner, poison, data } = self`. - let (inner, poison, data) = { - let RwLock { ref inner, ref poison, ref data } = self; - (ptr::read(inner), ptr::read(poison), ptr::read(data)) - }; - mem::forget(self); - inner.destroy(); // Keep in sync with the `Drop` impl. - drop(inner); - - poison::map_result(poison.borrow(), |_| data.into_inner()) - } + let data = self.data.into_inner(); + poison::map_result(self.poison.borrow(), |_| data) } /// Returns a mutable reference to the underlying data. @@ -425,14 +419,6 @@ impl<T: ?Sized> RwLock<T> { } #[stable(feature = "rust1", since = "1.0.0")] -unsafe impl<#[may_dangle] T: ?Sized> Drop for RwLock<T> { - fn drop(&mut self) { - // IMPORTANT: This code needs to be kept in sync with `RwLock::into_inner`. - unsafe { self.inner.destroy() } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] impl<T: ?Sized + fmt::Debug> fmt::Debug for RwLock<T> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let mut d = f.debug_struct("RwLock"); diff --git a/library/std/src/sys/common/alloc.rs b/library/std/src/sys/common/alloc.rs index 2a54e99020e..576667c0173 100644 --- a/library/std/src/sys/common/alloc.rs +++ b/library/std/src/sys/common/alloc.rs @@ -14,7 +14,8 @@ use crate::ptr; target_arch = "asmjs", target_arch = "wasm32", target_arch = "hexagon", - target_arch = "riscv32" + target_arch = "riscv32", + target_arch = "xtensa" )))] pub const MIN_ALIGN: usize = 8; #[cfg(all(any( diff --git a/library/std/src/sys/hermit/args.rs b/library/std/src/sys/hermit/args.rs index 4eb0d8437ba..1c7e1dd8d57 100644 --- a/library/std/src/sys/hermit/args.rs +++ b/library/std/src/sys/hermit/args.rs @@ -55,8 +55,8 @@ impl DoubleEndedIterator for Args { mod imp { use super::Args; use crate::ffi::{CStr, OsString}; + use crate::os::unix::ffi::OsStringExt; use crate::ptr; - use crate::sys_common::os_str_bytes::*; use crate::sys_common::mutex::StaticMutex; diff --git a/library/std/src/sys/hermit/condvar.rs b/library/std/src/sys/hermit/condvar.rs index b45e8718f08..fa8ef8fc37a 100644 --- a/library/std/src/sys/hermit/condvar.rs +++ b/library/std/src/sys/hermit/condvar.rs @@ -14,7 +14,7 @@ pub struct Condvar { sem2: *const c_void, } -pub type MovableCondvar = Box<Condvar>; +pub type MovableCondvar = Condvar; unsafe impl Send for Condvar {} unsafe impl Sync for Condvar {} diff --git a/library/std/src/sys/hermit/fs.rs b/library/std/src/sys/hermit/fs.rs index 76ea70d997f..be019d4435d 100644 --- a/library/std/src/sys/hermit/fs.rs +++ b/library/std/src/sys/hermit/fs.rs @@ -3,6 +3,7 @@ use crate::fmt; use crate::hash::{Hash, Hasher}; use crate::io::{self, Error, ErrorKind}; use crate::io::{IoSlice, IoSliceMut, SeekFrom}; +use crate::os::unix::ffi::OsStrExt; use crate::path::{Path, PathBuf}; use crate::sys::cvt; use crate::sys::hermit::abi; @@ -10,7 +11,6 @@ use crate::sys::hermit::abi::{O_APPEND, O_CREAT, O_EXCL, O_RDONLY, O_RDWR, O_TRU use crate::sys::hermit::fd::FileDesc; use crate::sys::time::SystemTime; use crate::sys::unsupported; -use crate::sys_common::os_str_bytes::OsStrExt; pub use crate::sys_common::fs::{copy, try_exists}; //pub use crate::sys_common::fs::remove_dir_all; diff --git a/library/std/src/sys/hermit/mod.rs b/library/std/src/sys/hermit/mod.rs index 15a76bbd2c9..185b68c0a78 100644 --- a/library/std/src/sys/hermit/mod.rs +++ b/library/std/src/sys/hermit/mod.rs @@ -32,6 +32,8 @@ pub mod memchr; pub mod mutex; pub mod net; pub mod os; +#[path = "../unix/os_str.rs"] +pub mod os_str; #[path = "../unix/path.rs"] pub mod path; #[path = "../unsupported/pipe.rs"] @@ -47,7 +49,6 @@ pub mod thread_local_key; pub mod time; use crate::io::ErrorKind; -pub use crate::sys_common::os_str_bytes as os_str; #[allow(unused_extern_crates)] pub extern crate hermit_abi as abi; @@ -149,7 +150,7 @@ pub fn decode_error_kind(errno: i32) -> ErrorKind { x if x == 1 as i32 => ErrorKind::PermissionDenied, x if x == 32 as i32 => ErrorKind::BrokenPipe, x if x == 110 as i32 => ErrorKind::TimedOut, - _ => ErrorKind::Other, + _ => ErrorKind::Uncategorized, } } diff --git a/library/std/src/sys/hermit/mutex.rs b/library/std/src/sys/hermit/mutex.rs index 885389ca54c..691e7e07902 100644 --- a/library/std/src/sys/hermit/mutex.rs +++ b/library/std/src/sys/hermit/mutex.rs @@ -14,7 +14,7 @@ use crate::sys::hermit::abi; /// This structure behaves a lot like a common mutex. There are some differences: /// /// - By using busy waiting, it can be used outside the runtime. -/// - It is a so called ticket lock and is completly fair. +/// - It is a so called ticket lock and is completely fair. #[cfg_attr(target_arch = "x86_64", repr(align(128)))] #[cfg_attr(not(target_arch = "x86_64"), repr(align(64)))] struct Spinlock<T: ?Sized> { @@ -156,7 +156,7 @@ pub struct Mutex { inner: Spinlock<MutexInner>, } -pub type MovableMutex = Box<Mutex>; +pub type MovableMutex = Mutex; unsafe impl Send for Mutex {} unsafe impl Sync for Mutex {} diff --git a/library/std/src/sys/hermit/net.rs b/library/std/src/sys/hermit/net.rs index 5f8839157ea..3f0c99cf742 100644 --- a/library/std/src/sys/hermit/net.rs +++ b/library/std/src/sys/hermit/net.rs @@ -15,7 +15,7 @@ use crate::time::Duration; pub fn init() -> io::Result<()> { if abi::network_init() < 0 { return Err(io::Error::new_const( - ErrorKind::Other, + ErrorKind::Uncategorized, &"Unable to initialize network interface", )); } @@ -51,7 +51,7 @@ impl TcpStream { match abi::tcpstream::connect(addr.ip().to_string().as_bytes(), addr.port(), None) { Ok(handle) => Ok(TcpStream(Arc::new(Socket(handle)))), _ => Err(io::Error::new_const( - ErrorKind::Other, + ErrorKind::Uncategorized, &"Unable to initiate a connection on a socket", )), } @@ -65,7 +65,7 @@ impl TcpStream { ) { Ok(handle) => Ok(TcpStream(Arc::new(Socket(handle)))), _ => Err(io::Error::new_const( - ErrorKind::Other, + ErrorKind::Uncategorized, &"Unable to initiate a connection on a socket", )), } @@ -73,7 +73,9 @@ impl TcpStream { pub fn set_read_timeout(&self, duration: Option<Duration>) -> io::Result<()> { abi::tcpstream::set_read_timeout(*self.0.as_inner(), duration.map(|d| d.as_millis() as u64)) - .map_err(|_| io::Error::new_const(ErrorKind::Other, &"Unable to set timeout value")) + .map_err(|_| { + io::Error::new_const(ErrorKind::Uncategorized, &"Unable to set timeout value") + }) } pub fn set_write_timeout(&self, duration: Option<Duration>) -> io::Result<()> { @@ -81,12 +83,12 @@ impl TcpStream { *self.0.as_inner(), duration.map(|d| d.as_millis() as u64), ) - .map_err(|_| io::Error::new_const(ErrorKind::Other, &"Unable to set timeout value")) + .map_err(|_| io::Error::new_const(ErrorKind::Uncategorized, &"Unable to set timeout value")) } pub fn read_timeout(&self) -> io::Result<Option<Duration>> { let duration = abi::tcpstream::get_read_timeout(*self.0.as_inner()).map_err(|_| { - io::Error::new_const(ErrorKind::Other, &"Unable to determine timeout value") + io::Error::new_const(ErrorKind::Uncategorized, &"Unable to determine timeout value") })?; Ok(duration.map(|d| Duration::from_millis(d))) @@ -94,7 +96,7 @@ impl TcpStream { pub fn write_timeout(&self) -> io::Result<Option<Duration>> { let duration = abi::tcpstream::get_write_timeout(*self.0.as_inner()).map_err(|_| { - io::Error::new_const(ErrorKind::Other, &"Unable to determine timeout value") + io::Error::new_const(ErrorKind::Uncategorized, &"Unable to determine timeout value") })?; Ok(duration.map(|d| Duration::from_millis(d))) @@ -102,7 +104,7 @@ impl TcpStream { pub fn peek(&self, buf: &mut [u8]) -> io::Result<usize> { abi::tcpstream::peek(*self.0.as_inner(), buf) - .map_err(|_| io::Error::new_const(ErrorKind::Other, &"set_nodelay failed")) + .map_err(|_| io::Error::new_const(ErrorKind::Uncategorized, &"peek failed")) } pub fn read(&self, buffer: &mut [u8]) -> io::Result<usize> { @@ -113,8 +115,9 @@ impl TcpStream { let mut size: usize = 0; for i in ioslice.iter_mut() { - let ret = abi::tcpstream::read(*self.0.as_inner(), &mut i[0..]) - .map_err(|_| io::Error::new_const(ErrorKind::Other, &"Unable to read on socket"))?; + let ret = abi::tcpstream::read(*self.0.as_inner(), &mut i[0..]).map_err(|_| { + io::Error::new_const(ErrorKind::Uncategorized, &"Unable to read on socket") + })?; if ret != 0 { size += ret; @@ -138,7 +141,7 @@ impl TcpStream { for i in ioslice.iter() { size += abi::tcpstream::write(*self.0.as_inner(), i).map_err(|_| { - io::Error::new_const(ErrorKind::Other, &"Unable to write on socket") + io::Error::new_const(ErrorKind::Uncategorized, &"Unable to write on socket") })?; } @@ -152,13 +155,13 @@ impl TcpStream { pub fn peer_addr(&self) -> io::Result<SocketAddr> { let (ipaddr, port) = abi::tcpstream::peer_addr(*self.0.as_inner()) - .map_err(|_| io::Error::new_const(ErrorKind::Other, &"peer_addr failed"))?; + .map_err(|_| io::Error::new_const(ErrorKind::Uncategorized, &"peer_addr failed"))?; let saddr = match ipaddr { Ipv4(ref addr) => SocketAddr::new(IpAddr::V4(Ipv4Addr::from(addr.0)), port), Ipv6(ref addr) => SocketAddr::new(IpAddr::V6(Ipv6Addr::from(addr.0)), port), _ => { - return Err(io::Error::new_const(ErrorKind::Other, &"peer_addr failed")); + return Err(io::Error::new_const(ErrorKind::Uncategorized, &"peer_addr failed")); } }; @@ -170,8 +173,9 @@ impl TcpStream { } pub fn shutdown(&self, how: Shutdown) -> io::Result<()> { - abi::tcpstream::shutdown(*self.0.as_inner(), how as i32) - .map_err(|_| io::Error::new_const(ErrorKind::Other, &"unable to shutdown socket")) + abi::tcpstream::shutdown(*self.0.as_inner(), how as i32).map_err(|_| { + io::Error::new_const(ErrorKind::Uncategorized, &"unable to shutdown socket") + }) } pub fn duplicate(&self) -> io::Result<TcpStream> { @@ -180,22 +184,22 @@ impl TcpStream { pub fn set_nodelay(&self, mode: bool) -> io::Result<()> { abi::tcpstream::set_nodelay(*self.0.as_inner(), mode) - .map_err(|_| io::Error::new_const(ErrorKind::Other, &"set_nodelay failed")) + .map_err(|_| io::Error::new_const(ErrorKind::Uncategorized, &"set_nodelay failed")) } pub fn nodelay(&self) -> io::Result<bool> { abi::tcpstream::nodelay(*self.0.as_inner()) - .map_err(|_| io::Error::new_const(ErrorKind::Other, &"nodelay failed")) + .map_err(|_| io::Error::new_const(ErrorKind::Uncategorized, &"nodelay failed")) } pub fn set_ttl(&self, tll: u32) -> io::Result<()> { abi::tcpstream::set_tll(*self.0.as_inner(), tll) - .map_err(|_| io::Error::new_const(ErrorKind::Other, &"unable to set TTL")) + .map_err(|_| io::Error::new_const(ErrorKind::Uncategorized, &"unable to set TTL")) } pub fn ttl(&self) -> io::Result<u32> { abi::tcpstream::get_tll(*self.0.as_inner()) - .map_err(|_| io::Error::new_const(ErrorKind::Other, &"unable to get TTL")) + .map_err(|_| io::Error::new_const(ErrorKind::Uncategorized, &"unable to get TTL")) } pub fn take_error(&self) -> io::Result<Option<io::Error>> { @@ -203,8 +207,9 @@ impl TcpStream { } pub fn set_nonblocking(&self, mode: bool) -> io::Result<()> { - abi::tcpstream::set_nonblocking(*self.0.as_inner(), mode) - .map_err(|_| io::Error::new_const(ErrorKind::Other, &"unable to set blocking mode")) + abi::tcpstream::set_nonblocking(*self.0.as_inner(), mode).map_err(|_| { + io::Error::new_const(ErrorKind::Uncategorized, &"unable to set blocking mode") + }) } } @@ -230,12 +235,12 @@ impl TcpListener { pub fn accept(&self) -> io::Result<(TcpStream, SocketAddr)> { let (handle, ipaddr, port) = abi::tcplistener::accept(self.0.port()) - .map_err(|_| io::Error::new_const(ErrorKind::Other, &"accept failed"))?; + .map_err(|_| io::Error::new_const(ErrorKind::Uncategorized, &"accept failed"))?; let saddr = match ipaddr { Ipv4(ref addr) => SocketAddr::new(IpAddr::V4(Ipv4Addr::from(addr.0)), port), Ipv6(ref addr) => SocketAddr::new(IpAddr::V6(Ipv6Addr::from(addr.0)), port), _ => { - return Err(io::Error::new_const(ErrorKind::Other, &"accept failed")); + return Err(io::Error::new_const(ErrorKind::Uncategorized, &"accept failed")); } }; diff --git a/library/std/src/sys/hermit/os.rs b/library/std/src/sys/hermit/os.rs index 40bd393098f..8f927df85be 100644 --- a/library/std/src/sys/hermit/os.rs +++ b/library/std/src/sys/hermit/os.rs @@ -4,13 +4,13 @@ use crate::ffi::{CStr, OsStr, OsString}; use crate::fmt; use crate::io; use crate::marker::PhantomData; +use crate::os::unix::ffi::OsStringExt; use crate::path::{self, PathBuf}; use crate::str; use crate::sync::Mutex; use crate::sys::hermit::abi; use crate::sys::memchr; use crate::sys::unsupported; -use crate::sys_common::os_str_bytes::*; use crate::vec; pub fn errno() -> i32 { @@ -140,13 +140,8 @@ pub fn env() -> Env { } } -pub fn getenv(k: &OsStr) -> io::Result<Option<OsString>> { - unsafe { - match ENV.as_ref().unwrap().lock().unwrap().get_mut(k) { - Some(value) => Ok(Some(value.clone())), - None => Ok(None), - } - } +pub fn getenv(k: &OsStr) -> Option<OsString> { + unsafe { ENV.as_ref().unwrap().lock().unwrap().get_mut(k).cloned() } } pub fn setenv(k: &OsStr, v: &OsStr) -> io::Result<()> { diff --git a/library/std/src/sys/hermit/rwlock.rs b/library/std/src/sys/hermit/rwlock.rs index 06442e925f4..64eaa2fc482 100644 --- a/library/std/src/sys/hermit/rwlock.rs +++ b/library/std/src/sys/hermit/rwlock.rs @@ -8,6 +8,8 @@ pub struct RWLock { state: UnsafeCell<State>, } +pub type MovableRWLock = RWLock; + enum State { Unlocked, Reading(usize), diff --git a/library/std/src/sys/hermit/stdio.rs b/library/std/src/sys/hermit/stdio.rs index 6bff13ca92c..33b8390431f 100644 --- a/library/std/src/sys/hermit/stdio.rs +++ b/library/std/src/sys/hermit/stdio.rs @@ -40,7 +40,7 @@ impl io::Write for Stdout { unsafe { len = abi::write(1, data.as_ptr() as *const u8, data.len()) } if len < 0 { - Err(io::Error::new_const(io::ErrorKind::Other, &"Stdout is not able to print")) + Err(io::Error::new_const(io::ErrorKind::Uncategorized, &"Stdout is not able to print")) } else { Ok(len as usize) } @@ -52,7 +52,7 @@ impl io::Write for Stdout { unsafe { len = abi::write(1, data.as_ptr() as *const u8, data.len()) } if len < 0 { - Err(io::Error::new_const(io::ErrorKind::Other, &"Stdout is not able to print")) + Err(io::Error::new_const(io::ErrorKind::Uncategorized, &"Stdout is not able to print")) } else { Ok(len as usize) } @@ -81,7 +81,7 @@ impl io::Write for Stderr { unsafe { len = abi::write(2, data.as_ptr() as *const u8, data.len()) } if len < 0 { - Err(io::Error::new_const(io::ErrorKind::Other, &"Stderr is not able to print")) + Err(io::Error::new_const(io::ErrorKind::Uncategorized, &"Stderr is not able to print")) } else { Ok(len as usize) } @@ -93,7 +93,7 @@ impl io::Write for Stderr { unsafe { len = abi::write(2, data.as_ptr() as *const u8, data.len()) } if len < 0 { - Err(io::Error::new_const(io::ErrorKind::Other, &"Stderr is not able to print")) + Err(io::Error::new_const(io::ErrorKind::Uncategorized, &"Stderr is not able to print")) } else { Ok(len as usize) } diff --git a/library/std/src/sys/hermit/thread.rs b/library/std/src/sys/hermit/thread.rs index f35a3a8a80f..8be25f84999 100644 --- a/library/std/src/sys/hermit/thread.rs +++ b/library/std/src/sys/hermit/thread.rs @@ -1,8 +1,10 @@ #![allow(dead_code)] +use super::unsupported; use crate::ffi::CStr; use crate::io; use crate::mem; +use crate::num::NonZeroUsize; use crate::sys::hermit::abi; use crate::sys::hermit::thread_local_dtor::run_dtors; use crate::time::Duration; @@ -37,7 +39,7 @@ impl Thread { // The thread failed to start and as a result p was not consumed. Therefore, it is // safe to reconstruct the box so that it gets deallocated. drop(Box::from_raw(p)); - Err(io::Error::new_const(io::ErrorKind::Other, &"Unable to create thread!")) + Err(io::Error::new_const(io::ErrorKind::Uncategorized, &"Unable to create thread!")) } else { Ok(Thread { tid: tid }) }; @@ -95,6 +97,10 @@ impl Thread { } } +pub fn available_concurrency() -> io::Result<NonZeroUsize> { + unsupported() +} + pub mod guard { pub type Guard = !; pub unsafe fn current() -> Option<Guard> { diff --git a/library/std/src/sys/sgx/abi/mem.rs b/library/std/src/sys/sgx/abi/mem.rs index 1e743894a9f..52e8bec937c 100644 --- a/library/std/src/sys/sgx/abi/mem.rs +++ b/library/std/src/sys/sgx/abi/mem.rs @@ -36,9 +36,9 @@ pub fn image_base() -> u64 { let base: u64; unsafe { asm!( - "lea {}, qword ptr [rip + IMAGE_BASE]", + "lea IMAGE_BASE(%rip), {}", lateout(reg) base, - options(nostack, preserves_flags, nomem, pure), + options(att_syntax, nostack, preserves_flags, nomem, pure), ) }; base diff --git a/library/std/src/sys/sgx/mod.rs b/library/std/src/sys/sgx/mod.rs index cdfceca19fc..a2a763c2b4e 100644 --- a/library/std/src/sys/sgx/mod.rs +++ b/library/std/src/sys/sgx/mod.rs @@ -26,6 +26,8 @@ pub mod memchr; pub mod mutex; pub mod net; pub mod os; +#[path = "../unix/os_str.rs"] +pub mod os_str; pub mod path; #[path = "../unsupported/pipe.rs"] pub mod pipe; @@ -37,8 +39,6 @@ pub mod thread; pub mod thread_local_key; pub mod time; -pub use crate::sys_common::os_str_bytes as os_str; - // SAFETY: must be called only once during runtime initialization. // NOTE: this is not guaranteed to run, for example when Rust code is called externally. pub unsafe fn init(argc: isize, argv: *const *const u8) { @@ -70,7 +70,7 @@ pub fn sgx_ineffective<T>(v: T) -> crate::io::Result<T> { static SGX_INEFFECTIVE_ERROR: AtomicBool = AtomicBool::new(false); if SGX_INEFFECTIVE_ERROR.load(Ordering::Relaxed) { Err(crate::io::Error::new_const( - ErrorKind::Other, + ErrorKind::Uncategorized, &"operation can't be trusted to have any effect on SGX", )) } else { @@ -115,11 +115,11 @@ pub fn decode_error_kind(code: i32) -> ErrorKind { } else if code == Error::Interrupted as _ { ErrorKind::Interrupted } else if code == Error::Other as _ { - ErrorKind::Other + ErrorKind::Uncategorized } else if code == Error::UnexpectedEof as _ { ErrorKind::UnexpectedEof } else { - ErrorKind::Other + ErrorKind::Uncategorized } } diff --git a/library/std/src/sys/sgx/mutex.rs b/library/std/src/sys/sgx/mutex.rs index 1b5ced4178f..0b2d1f4487f 100644 --- a/library/std/src/sys/sgx/mutex.rs +++ b/library/std/src/sys/sgx/mutex.rs @@ -8,7 +8,8 @@ pub struct Mutex { inner: SpinMutex<WaitVariable<bool>>, } -pub type MovableMutex = Mutex; +// not movable: see UnsafeList implementation +pub type MovableMutex = Box<Mutex>; // Implementation according to “Operating Systems: Three Easy Pieces”, chapter 28 impl Mutex { diff --git a/library/std/src/sys/sgx/net.rs b/library/std/src/sys/sgx/net.rs index 5ccedece0f8..3a69aa039ef 100644 --- a/library/std/src/sys/sgx/net.rs +++ b/library/std/src/sys/sgx/net.rs @@ -466,7 +466,7 @@ pub struct LookupHost(!); impl LookupHost { fn new(host: String) -> io::Result<LookupHost> { - Err(io::Error::new(io::ErrorKind::Other, NonIpSockAddr { host })) + Err(io::Error::new(io::ErrorKind::Uncategorized, NonIpSockAddr { host })) } pub fn port(&self) -> u16 { diff --git a/library/std/src/sys/sgx/os.rs b/library/std/src/sys/sgx/os.rs index 144248d60c9..5f8b8def7c6 100644 --- a/library/std/src/sys/sgx/os.rs +++ b/library/std/src/sys/sgx/os.rs @@ -106,8 +106,8 @@ pub fn env() -> Env { get_env_store().map(|env| clone_to_vec(&env.lock().unwrap())).unwrap_or_default().into_iter() } -pub fn getenv(k: &OsStr) -> io::Result<Option<OsString>> { - Ok(get_env_store().and_then(|s| s.lock().unwrap().get(k).cloned())) +pub fn getenv(k: &OsStr) -> Option<OsString> { + get_env_store().and_then(|s| s.lock().unwrap().get(k).cloned()) } pub fn setenv(k: &OsStr, v: &OsStr) -> io::Result<()> { diff --git a/library/std/src/sys/sgx/rwlock.rs b/library/std/src/sys/sgx/rwlock.rs index 0c96e3fcddc..2d038b51896 100644 --- a/library/std/src/sys/sgx/rwlock.rs +++ b/library/std/src/sys/sgx/rwlock.rs @@ -13,6 +13,8 @@ pub struct RWLock { writer: SpinMutex<WaitVariable<bool>>, } +pub type MovableRWLock = Box<RWLock>; + // Check at compile time that RWLock size matches C definition (see test_c_rwlock_initializer below) // // # Safety diff --git a/library/std/src/sys/sgx/stdio.rs b/library/std/src/sys/sgx/stdio.rs index 548e28a43d6..8ccf043b5b5 100644 --- a/library/std/src/sys/sgx/stdio.rs +++ b/library/std/src/sys/sgx/stdio.rs @@ -65,7 +65,7 @@ impl io::Write for Stderr { pub const STDIN_BUF_SIZE: usize = crate::sys_common::io::DEFAULT_BUF_SIZE; pub fn is_ebadf(err: &io::Error) -> bool { - // FIXME: Rust normally maps Unix EBADF to `Other` + // FIXME: Rust normally maps Unix EBADF to `Uncategorized` err.raw_os_error() == Some(abi::Error::BrokenPipe as _) } diff --git a/library/std/src/sys/sgx/thread.rs b/library/std/src/sys/sgx/thread.rs index 67e2e8b59d3..cbb8ba96401 100644 --- a/library/std/src/sys/sgx/thread.rs +++ b/library/std/src/sys/sgx/thread.rs @@ -1,6 +1,8 @@ #![cfg_attr(test, allow(dead_code))] // why is this necessary? +use super::unsupported; use crate::ffi::CStr; use crate::io; +use crate::num::NonZeroUsize; use crate::time::Duration; use super::abi::usercalls; @@ -135,6 +137,10 @@ impl Thread { } } +pub fn available_concurrency() -> io::Result<NonZeroUsize> { + unsupported() +} + pub mod guard { pub type Guard = !; pub unsafe fn current() -> Option<Guard> { diff --git a/library/std/src/sys/sgx/waitqueue/unsafe_list.rs b/library/std/src/sys/sgx/waitqueue/unsafe_list.rs index cf2f0886c15..c736cab576e 100644 --- a/library/std/src/sys/sgx/waitqueue/unsafe_list.rs +++ b/library/std/src/sys/sgx/waitqueue/unsafe_list.rs @@ -23,6 +23,7 @@ impl<T> UnsafeListEntry<T> { } } +// WARNING: self-referential struct! pub struct UnsafeList<T> { head_tail: NonNull<UnsafeListEntry<T>>, head_tail_entry: Option<UnsafeListEntry<T>>, diff --git a/library/std/src/sys/unix/alloc.rs b/library/std/src/sys/unix/alloc.rs index 1b71905aa09..7c3d9573940 100644 --- a/library/std/src/sys/unix/alloc.rs +++ b/library/std/src/sys/unix/alloc.rs @@ -57,7 +57,8 @@ cfg_if::cfg_if! { target_os = "android", target_os = "illumos", target_os = "redox", - target_os = "solaris" + target_os = "solaris", + target_os = "espidf" ))] { #[inline] unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 { diff --git a/library/std/src/sys/unix/android.rs b/library/std/src/sys/unix/android.rs index cf6aa31b7cf..6a46525f682 100644 --- a/library/std/src/sys/unix/android.rs +++ b/library/std/src/sys/unix/android.rs @@ -21,7 +21,7 @@ use libc::{c_int, c_void, sighandler_t, size_t, ssize_t}; use libc::{ftruncate, pread, pwrite}; -use super::{cvt, cvt_r}; +use super::{cvt, cvt_r, weak::weak}; use crate::io; // The `log2` and `log2f` functions apparently appeared in android-18, or at diff --git a/library/std/src/sys/unix/args.rs b/library/std/src/sys/unix/args.rs index fc423e393d4..ee5e3983ac2 100644 --- a/library/std/src/sys/unix/args.rs +++ b/library/std/src/sys/unix/args.rs @@ -14,11 +14,6 @@ pub unsafe fn init(argc: isize, argv: *const *const u8) { imp::init(argc, argv) } -/// One-time global cleanup. -pub unsafe fn cleanup() { - imp::cleanup() -} - /// Returns the command line arguments pub fn args() -> Args { imp::args() @@ -82,16 +77,18 @@ mod imp { use crate::ptr; use crate::sync::atomic::{AtomicIsize, AtomicPtr, Ordering}; - use crate::sys_common::mutex::StaticMutex; - + // The system-provided argc and argv, which we store in static memory + // here so that we can defer the work of parsing them until its actually + // needed. + // + // Note that we never mutate argv/argc, the argv array, or the argv + // strings, which allows the code in this file to be very simple. static ARGC: AtomicIsize = AtomicIsize::new(0); static ARGV: AtomicPtr<*const u8> = AtomicPtr::new(ptr::null_mut()); - // We never call `ENV_LOCK.init()`, so it is UB to attempt to - // acquire this mutex reentrantly! - static LOCK: StaticMutex = StaticMutex::new(); unsafe fn really_init(argc: isize, argv: *const *const u8) { - let _guard = LOCK.lock(); + // These don't need to be ordered with each other or other stores, + // because they only hold the unmodified system-provide argv/argc. ARGC.store(argc, Ordering::Relaxed); ARGV.store(argv as *mut _, Ordering::Relaxed); } @@ -127,21 +124,22 @@ mod imp { init_wrapper }; - pub unsafe fn cleanup() { - let _guard = LOCK.lock(); - ARGC.store(0, Ordering::Relaxed); - ARGV.store(ptr::null_mut(), Ordering::Relaxed); - } - pub fn args() -> Args { Args { iter: clone().into_iter() } } fn clone() -> Vec<OsString> { unsafe { - let _guard = LOCK.lock(); - let argc = ARGC.load(Ordering::Relaxed); + // Load ARGC and ARGV, which hold the unmodified system-provided + // argc/argv, so we can read the pointed-to memory without atomics + // or synchronization. + // + // If either ARGC or ARGV is still zero or null, then either there + // really are no arguments, or someone is asking for `args()` + // before initialization has completed, and we return an empty + // list. let argv = ARGV.load(Ordering::Relaxed); + let argc = if argv.is_null() { 0 } else { ARGC.load(Ordering::Relaxed) }; (0..argc) .map(|i| { let cstr = CStr::from_ptr(*argv.offset(i) as *const libc::c_char); @@ -159,8 +157,6 @@ mod imp { pub unsafe fn init(_argc: isize, _argv: *const *const u8) {} - pub fn cleanup() {} - #[cfg(target_os = "macos")] pub fn args() -> Args { use crate::os::unix::prelude::*; @@ -250,3 +246,15 @@ mod imp { Args { iter: res.into_iter() } } } + +#[cfg(target_os = "espidf")] +mod imp { + use super::Args; + + #[inline(always)] + pub unsafe fn init(_argc: isize, _argv: *const *const u8) {} + + pub fn args() -> Args { + Args { iter: Vec::new().into_iter() } + } +} diff --git a/library/std/src/sys/unix/condvar.rs b/library/std/src/sys/unix/condvar.rs index e38f91af9f0..61261c0aa84 100644 --- a/library/std/src/sys/unix/condvar.rs +++ b/library/std/src/sys/unix/condvar.rs @@ -34,12 +34,23 @@ impl Condvar { ))] pub unsafe fn init(&mut self) {} + // NOTE: ESP-IDF's PTHREAD_COND_INITIALIZER support is not released yet + // So on that platform, init() should always be called + // Moreover, that platform does not have pthread_condattr_setclock support, + // hence that initialization should be skipped as well + #[cfg(target_os = "espidf")] + pub unsafe fn init(&mut self) { + let r = libc::pthread_cond_init(self.inner.get(), crate::ptr::null()); + assert_eq!(r, 0); + } + #[cfg(not(any( target_os = "macos", target_os = "ios", target_os = "l4re", target_os = "android", - target_os = "redox" + target_os = "redox", + target_os = "espidf" )))] pub unsafe fn init(&mut self) { use crate::mem::MaybeUninit; @@ -76,7 +87,12 @@ impl Condvar { // where we configure condition variable to use monotonic clock (instead of // default system clock). This approach avoids all problems that result // from changes made to the system time. - #[cfg(not(any(target_os = "macos", target_os = "ios", target_os = "android")))] + #[cfg(not(any( + target_os = "macos", + target_os = "ios", + target_os = "android", + target_os = "espidf" + )))] pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool { use crate::mem; @@ -103,7 +119,12 @@ impl Condvar { // This implementation is modeled after libcxx's condition_variable // https://github.com/llvm-mirror/libcxx/blob/release_35/src/condition_variable.cpp#L46 // https://github.com/llvm-mirror/libcxx/blob/release_35/include/__mutex_base#L367 - #[cfg(any(target_os = "macos", target_os = "ios", target_os = "android"))] + #[cfg(any( + target_os = "macos", + target_os = "ios", + target_os = "android", + target_os = "espidf" + ))] pub unsafe fn wait_timeout(&self, mutex: &Mutex, mut dur: Duration) -> bool { use crate::ptr; use crate::time::Instant; diff --git a/library/std/src/sys/unix/env.rs b/library/std/src/sys/unix/env.rs index 3a88dc083b0..60551aeb3e7 100644 --- a/library/std/src/sys/unix/env.rs +++ b/library/std/src/sys/unix/env.rs @@ -184,3 +184,14 @@ pub mod os { pub const EXE_SUFFIX: &str = ""; pub const EXE_EXTENSION: &str = ""; } + +#[cfg(target_os = "espidf")] +pub mod os { + pub const FAMILY: &str = "unix"; + pub const OS: &str = "espidf"; + pub const DLL_PREFIX: &str = "lib"; + pub const DLL_SUFFIX: &str = ".so"; + pub const DLL_EXTENSION: &str = "so"; + pub const EXE_SUFFIX: &str = ""; + pub const EXE_EXTENSION: &str = ""; +} diff --git a/library/std/src/sys/unix/fd.rs b/library/std/src/sys/unix/fd.rs index 821851a6c65..28e32681e15 100644 --- a/library/std/src/sys/unix/fd.rs +++ b/library/std/src/sys/unix/fd.rs @@ -91,6 +91,7 @@ impl FileDesc { Ok(ret as usize) } + #[cfg(not(target_os = "espidf"))] pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> { let ret = cvt(unsafe { libc::readv( @@ -102,9 +103,14 @@ impl FileDesc { Ok(ret as usize) } + #[cfg(target_os = "espidf")] + pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> { + return crate::io::default_read_vectored(|b| self.read(b), bufs); + } + #[inline] pub fn is_read_vectored(&self) -> bool { - true + cfg!(not(target_os = "espidf")) } pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> { @@ -148,6 +154,7 @@ impl FileDesc { Ok(ret as usize) } + #[cfg(not(target_os = "espidf"))] pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> { let ret = cvt(unsafe { libc::writev( @@ -159,9 +166,14 @@ impl FileDesc { Ok(ret as usize) } + #[cfg(target_os = "espidf")] + pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> { + return crate::io::default_write_vectored(|b| self.write(b), bufs); + } + #[inline] pub fn is_write_vectored(&self) -> bool { - true + cfg!(not(target_os = "espidf")) } pub fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> { @@ -217,7 +229,7 @@ impl FileDesc { } } #[cfg(any( - target_env = "newlib", + all(target_env = "newlib", not(target_os = "espidf")), target_os = "solaris", target_os = "illumos", target_os = "emscripten", @@ -238,6 +250,12 @@ impl FileDesc { Ok(()) } } + #[cfg(target_os = "espidf")] + pub fn set_cloexec(&self) -> io::Result<()> { + // FD_CLOEXEC is not supported in ESP-IDF but there's no need to, + // because ESP-IDF does not support spawning processes either. + Ok(()) + } #[cfg(target_os = "linux")] pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { @@ -268,7 +286,17 @@ impl FileDesc { // We want to atomically duplicate this file descriptor and set the // CLOEXEC flag, and currently that's done via F_DUPFD_CLOEXEC. This // is a POSIX flag that was added to Linux in 2.6.24. - let fd = cvt(unsafe { libc::fcntl(self.raw(), libc::F_DUPFD_CLOEXEC, 0) })?; + #[cfg(not(target_os = "espidf"))] + let cmd = libc::F_DUPFD_CLOEXEC; + + // For ESP-IDF, F_DUPFD is used instead, because the CLOEXEC semantics + // will never be supported, as this is a bare metal framework with + // no capabilities for multi-process execution. While F_DUPFD is also + // not supported yet, it might be (currently it returns ENOSYS). + #[cfg(target_os = "espidf")] + let cmd = libc::F_DUPFD; + + let fd = cvt(unsafe { libc::fcntl(self.raw(), cmd, 0) })?; Ok(FileDesc::new(fd)) } } diff --git a/library/std/src/sys/unix/fs.rs b/library/std/src/sys/unix/fs.rs index f8ca67c844c..fd4defd72eb 100644 --- a/library/std/src/sys/unix/fs.rs +++ b/library/std/src/sys/unix/fs.rs @@ -12,8 +12,23 @@ use crate::sys::time::SystemTime; use crate::sys::{cvt, cvt_r}; use crate::sys_common::{AsInner, FromInner}; +#[cfg(any( + all(target_os = "linux", target_env = "gnu"), + target_os = "macos", + target_os = "ios", +))] +use crate::sys::weak::syscall; +#[cfg(target_os = "macos")] +use crate::sys::weak::weak; + use libc::{c_int, mode_t}; +#[cfg(any( + target_os = "macos", + target_os = "ios", + all(target_os = "linux", target_env = "gnu") +))] +use libc::c_char; #[cfg(any(target_os = "linux", target_os = "emscripten", target_os = "android"))] use libc::dirfd; #[cfg(any(target_os = "linux", target_os = "emscripten"))] @@ -92,7 +107,7 @@ cfg_has_statx! {{ // Default `stat64` contains no creation time. unsafe fn try_statx( fd: c_int, - path: *const libc::c_char, + path: *const c_char, flags: i32, mask: u32, ) -> Option<io::Result<FileAttr>> { @@ -107,7 +122,7 @@ cfg_has_statx! {{ syscall! { fn statx( fd: c_int, - pathname: *const libc::c_char, + pathname: *const c_char, flags: c_int, mask: libc::c_uint, statxbuf: *mut libc::statx @@ -297,7 +312,7 @@ impl FileAttr { #[cfg(not(target_os = "netbsd"))] impl FileAttr { - #[cfg(not(target_os = "vxworks"))] + #[cfg(all(not(target_os = "vxworks"), not(target_os = "espidf")))] pub fn modified(&self) -> io::Result<SystemTime> { Ok(SystemTime::from(libc::timespec { tv_sec: self.stat.st_mtime as libc::time_t, @@ -305,7 +320,7 @@ impl FileAttr { })) } - #[cfg(target_os = "vxworks")] + #[cfg(any(target_os = "vxworks", target_os = "espidf"))] pub fn modified(&self) -> io::Result<SystemTime> { Ok(SystemTime::from(libc::timespec { tv_sec: self.stat.st_mtime as libc::time_t, @@ -313,7 +328,7 @@ impl FileAttr { })) } - #[cfg(not(target_os = "vxworks"))] + #[cfg(all(not(target_os = "vxworks"), not(target_os = "espidf")))] pub fn accessed(&self) -> io::Result<SystemTime> { Ok(SystemTime::from(libc::timespec { tv_sec: self.stat.st_atime as libc::time_t, @@ -321,7 +336,7 @@ impl FileAttr { })) } - #[cfg(target_os = "vxworks")] + #[cfg(any(target_os = "vxworks", target_os = "espidf"))] pub fn accessed(&self) -> io::Result<SystemTime> { Ok(SystemTime::from(libc::timespec { tv_sec: self.stat.st_atime as libc::time_t, @@ -358,7 +373,7 @@ impl FileAttr { })) } else { Err(io::Error::new_const( - io::ErrorKind::Other, + io::ErrorKind::Uncategorized, &"creation time is not available for the filesystem", )) }; @@ -594,7 +609,8 @@ impl DirEntry { target_os = "l4re", target_os = "fuchsia", target_os = "redox", - target_os = "vxworks" + target_os = "vxworks", + target_os = "espidf" ))] pub fn ino(&self) -> u64 { self.entry.d_ino as u64 @@ -633,7 +649,8 @@ impl DirEntry { target_os = "emscripten", target_os = "l4re", target_os = "haiku", - target_os = "vxworks" + target_os = "vxworks", + target_os = "espidf" ))] fn name_bytes(&self) -> &[u8] { unsafe { CStr::from_ptr(self.entry.d_name.as_ptr()).to_bytes() } @@ -647,6 +664,10 @@ impl DirEntry { fn name_bytes(&self) -> &[u8] { &*self.name } + + pub fn file_name_os_str(&self) -> &OsStr { + OsStr::from_bytes(self.name_bytes()) + } } impl OpenOptions { @@ -752,7 +773,7 @@ impl File { cfg_has_statx! { if let Some(ret) = unsafe { try_statx( fd, - b"\0" as *const _ as *const libc::c_char, + b"\0" as *const _ as *const c_char, libc::AT_EMPTY_PATH | libc::AT_STATX_SYNC_AS_STAT, libc::STATX_ALL, ) } { @@ -920,7 +941,7 @@ impl FromInner<c_int> for File { impl fmt::Debug for File { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - #[cfg(target_os = "linux")] + #[cfg(any(target_os = "linux", target_os = "netbsd"))] fn get_path(fd: c_int) -> Option<PathBuf> { let mut p = PathBuf::from("/proc/self/fd"); p.push(&fd.to_string()); @@ -957,7 +978,12 @@ impl fmt::Debug for File { Some(PathBuf::from(OsString::from_vec(buf))) } - #[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "vxworks")))] + #[cfg(not(any( + target_os = "linux", + target_os = "macos", + target_os = "vxworks", + target_os = "netbsd" + )))] fn get_path(_fd: c_int) -> Option<PathBuf> { // FIXME(#24570): implement this for other Unix platforms None @@ -1082,16 +1108,29 @@ pub fn link(original: &Path, link: &Path) -> io::Result<()> { let original = cstr(original)?; let link = cstr(link)?; cfg_if::cfg_if! { - if #[cfg(any(target_os = "vxworks", target_os = "redox", target_os = "android"))] { - // VxWorks, Redox, and old versions of Android lack `linkat`, so use - // `link` instead. POSIX leaves it implementation-defined whether - // `link` follows symlinks, so rely on the `symlink_hard_link` test - // in library/std/src/fs/tests.rs to check the behavior. + if #[cfg(any(target_os = "vxworks", target_os = "redox", target_os = "android", target_os = "espidf"))] { + // VxWorks, Redox and ESP-IDF lack `linkat`, so use `link` instead. POSIX leaves + // it implementation-defined whether `link` follows symlinks, so rely on the + // `symlink_hard_link` test in library/std/src/fs/tests.rs to check the behavior. + // Android has `linkat` on newer versions, but we happen to know `link` + // always has the correct behavior, so it's here as well. cvt(unsafe { libc::link(original.as_ptr(), link.as_ptr()) })?; + } else if #[cfg(target_os = "macos")] { + // On MacOS, older versions (<=10.9) lack support for linkat while newer + // versions have it. We want to use linkat if it is available, so we use weak! + // to check. `linkat` is preferable to `link` ecause it gives us a flag to + // specify how symlinks should be handled. We pass 0 as the flags argument, + // meaning it shouldn't follow symlinks. + weak!(fn linkat(c_int, *const c_char, c_int, *const c_char, c_int) -> c_int); + + if let Some(f) = linkat.get() { + cvt(unsafe { f(libc::AT_FDCWD, original.as_ptr(), libc::AT_FDCWD, link.as_ptr(), 0) })?; + } else { + cvt(unsafe { libc::link(original.as_ptr(), link.as_ptr()) })?; + }; } else { - // Use `linkat` with `AT_FDCWD` instead of `link` as `linkat` gives - // us a flag to specify how symlinks should be handled. Pass 0 as - // the flags argument, meaning don't follow symlinks. + // Where we can, use `linkat` instead of `link`; see the comment above + // this one for details on why. cvt(unsafe { libc::linkat(libc::AT_FDCWD, original.as_ptr(), libc::AT_FDCWD, link.as_ptr(), 0) })?; } } @@ -1162,6 +1201,18 @@ fn open_from(from: &Path) -> io::Result<(crate::fs::File, crate::fs::Metadata)> Ok((reader, metadata)) } +#[cfg(target_os = "espidf")] +fn open_to_and_set_permissions( + to: &Path, + reader_metadata: crate::fs::Metadata, +) -> io::Result<(crate::fs::File, crate::fs::Metadata)> { + use crate::fs::OpenOptions; + let writer = OpenOptions::new().open(to)?; + let writer_metadata = writer.metadata()?; + Ok((writer, writer_metadata)) +} + +#[cfg(not(target_os = "espidf"))] fn open_to_and_set_permissions( to: &Path, reader_metadata: crate::fs::Metadata, @@ -1274,7 +1325,7 @@ pub fn copy(from: &Path, to: &Path) -> io::Result<u64> { fn fclonefileat( srcfd: libc::c_int, dst_dirfd: libc::c_int, - dst: *const libc::c_char, + dst: *const c_char, flags: libc::c_int ) -> libc::c_int } diff --git a/library/std/src/sys/unix/kernel_copy.rs b/library/std/src/sys/unix/kernel_copy.rs index 9687576bb6a..a6b43229ba6 100644 --- a/library/std/src/sys/unix/kernel_copy.rs +++ b/library/std/src/sys/unix/kernel_copy.rs @@ -61,6 +61,7 @@ use crate::process::{ChildStderr, ChildStdin, ChildStdout}; use crate::ptr; use crate::sync::atomic::{AtomicBool, AtomicU8, Ordering}; use crate::sys::cvt; +use crate::sys::weak::syscall; use libc::{EBADF, EINVAL, ENOSYS, EOPNOTSUPP, EOVERFLOW, EPERM, EXDEV}; #[cfg(test)] diff --git a/library/std/src/sys/unix/mod.rs b/library/std/src/sys/unix/mod.rs index ca9cc8ca7ba..f5424e3d282 100644 --- a/library/std/src/sys/unix/mod.rs +++ b/library/std/src/sys/unix/mod.rs @@ -5,6 +5,7 @@ use crate::io::ErrorKind; pub use self::rand::hashmap_random_keys; pub use libc::strlen; +#[cfg(not(target_os = "espidf"))] #[macro_use] pub mod weak; @@ -30,6 +31,7 @@ pub mod net; #[cfg(target_os = "l4re")] pub use self::l4re::net; pub mod os; +pub mod os_str; pub mod path; pub mod pipe; pub mod process; @@ -42,8 +44,10 @@ pub mod thread_local_dtor; pub mod thread_local_key; pub mod time; -pub use crate::sys_common::os_str_bytes as os_str; +#[cfg(target_os = "espidf")] +pub fn init(argc: isize, argv: *const *const u8) {} +#[cfg(not(target_os = "espidf"))] // SAFETY: must be called only once during runtime initialization. // NOTE: this is not guaranteed to run, for example when Rust code is called externally. pub unsafe fn init(argc: isize, argv: *const *const u8) { @@ -123,7 +127,6 @@ pub unsafe fn init(argc: isize, argv: *const *const u8) { // SAFETY: must be called only once during runtime cleanup. // NOTE: this is not guaranteed to run, for example when the program aborts. pub unsafe fn cleanup() { - args::cleanup(); stack_overflow::cleanup(); } @@ -133,29 +136,51 @@ pub use crate::sys::android::signal; pub use libc::signal; pub fn decode_error_kind(errno: i32) -> ErrorKind { + use ErrorKind::*; match errno as libc::c_int { - libc::ECONNREFUSED => ErrorKind::ConnectionRefused, - libc::ECONNRESET => ErrorKind::ConnectionReset, - libc::EPERM | libc::EACCES => ErrorKind::PermissionDenied, - libc::EPIPE => ErrorKind::BrokenPipe, - libc::ENOTCONN => ErrorKind::NotConnected, - libc::ECONNABORTED => ErrorKind::ConnectionAborted, - libc::EADDRNOTAVAIL => ErrorKind::AddrNotAvailable, - libc::EADDRINUSE => ErrorKind::AddrInUse, - libc::ENOENT => ErrorKind::NotFound, - libc::EINTR => ErrorKind::Interrupted, - libc::EINVAL => ErrorKind::InvalidInput, - libc::ETIMEDOUT => ErrorKind::TimedOut, - libc::EEXIST => ErrorKind::AlreadyExists, - libc::ENOSYS => ErrorKind::Unsupported, - libc::ENOMEM => ErrorKind::OutOfMemory, + libc::E2BIG => ArgumentListTooLong, + libc::EADDRINUSE => AddrInUse, + libc::EADDRNOTAVAIL => AddrNotAvailable, + libc::EBUSY => ResourceBusy, + libc::ECONNABORTED => ConnectionAborted, + libc::ECONNREFUSED => ConnectionRefused, + libc::ECONNRESET => ConnectionReset, + libc::EDEADLK => Deadlock, + libc::EDQUOT => FilesystemQuotaExceeded, + libc::EEXIST => AlreadyExists, + libc::EFBIG => FileTooLarge, + libc::EHOSTUNREACH => HostUnreachable, + libc::EINTR => Interrupted, + libc::EINVAL => InvalidInput, + libc::EISDIR => IsADirectory, + libc::ELOOP => FilesystemLoop, + libc::ENOENT => NotFound, + libc::ENOMEM => OutOfMemory, + libc::ENOSPC => StorageFull, + libc::ENOSYS => Unsupported, + libc::EMLINK => TooManyLinks, + libc::ENAMETOOLONG => FilenameTooLong, + libc::ENETDOWN => NetworkDown, + libc::ENETUNREACH => NetworkUnreachable, + libc::ENOTCONN => NotConnected, + libc::ENOTDIR => NotADirectory, + libc::ENOTEMPTY => DirectoryNotEmpty, + libc::EPIPE => BrokenPipe, + libc::EROFS => ReadOnlyFilesystem, + libc::ESPIPE => NotSeekable, + libc::ESTALE => StaleNetworkFileHandle, + libc::ETIMEDOUT => TimedOut, + libc::ETXTBSY => ExecutableFileBusy, + libc::EXDEV => CrossesDevices, + + libc::EACCES | libc::EPERM => PermissionDenied, // These two constants can have the same value on some systems, // but different values on others, so we can't use a match // clause - x if x == libc::EAGAIN || x == libc::EWOULDBLOCK => ErrorKind::WouldBlock, + x if x == libc::EAGAIN || x == libc::EWOULDBLOCK => WouldBlock, - _ => ErrorKind::Other, + _ => Uncategorized, } } @@ -195,13 +220,41 @@ pub fn cvt_nz(error: libc::c_int) -> crate::io::Result<()> { if error == 0 { Ok(()) } else { Err(crate::io::Error::from_raw_os_error(error)) } } -// On Unix-like platforms, libc::abort will unregister signal handlers -// including the SIGABRT handler, preventing the abort from being blocked, and -// fclose streams, with the side effect of flushing them so libc buffered -// output will be printed. Additionally the shell will generally print a more -// understandable error message like "Abort trap" rather than "Illegal -// instruction" that intrinsics::abort would cause, as intrinsics::abort is -// implemented as an illegal instruction. +// libc::abort() will run the SIGABRT handler. That's fine because anyone who +// installs a SIGABRT handler already has to expect it to run in Very Bad +// situations (eg, malloc crashing). +// +// Current glibc's abort() function unblocks SIGABRT, raises SIGABRT, clears the +// SIGABRT handler and raises it again, and then starts to get creative. +// +// See the public documentation for `intrinsics::abort()` and `process::abort()` +// for further discussion. +// +// There is confusion about whether libc::abort() flushes stdio streams. +// libc::abort() is required by ISO C 99 (7.14.1.1p5) to be async-signal-safe, +// so flushing streams is at least extremely hard, if not entirely impossible. +// +// However, some versions of POSIX (eg IEEE Std 1003.1-2001) required abort to +// do so. In 1003.1-2004 this was fixed. +// +// glibc's implementation did the flush, unsafely, before glibc commit +// 91e7cf982d01 `abort: Do not flush stdio streams [BZ #15436]' by Florian +// Weimer. According to glibc's NEWS: +// +// The abort function terminates the process immediately, without flushing +// stdio streams. Previous glibc versions used to flush streams, resulting +// in deadlocks and further data corruption. This change also affects +// process aborts as the result of assertion failures. +// +// This is an accurate description of the problem. The only solution for +// program with nontrivial use of C stdio is a fixed libc - one which does not +// try to flush in abort - since even libc-internal errors, and assertion +// failures generated from C, will go via abort(). +// +// On systems with old, buggy, libcs, the impact can be severe for a +// multithreaded C program. It is much less severe for Rust, because Rust +// stdlib doesn't use libc stdio buffering. In a typical Rust program, which +// does not use C stdio, even a buggy libc::abort() is, in fact, safe. pub fn abort_internal() -> ! { unsafe { libc::abort() } } @@ -240,7 +293,7 @@ cfg_if::cfg_if! { } else if #[cfg(target_os = "macos")] { #[link(name = "System")] // res_init and friends require -lresolv on macOS/iOS. - // See #41582 and http://blog.achernya.com/2013/03/os-x-has-silly-libsystem.html + // See #41582 and https://blog.achernya.com/2013/03/os-x-has-silly-libsystem.html #[link(name = "resolv")] extern "C" {} } else if #[cfg(target_os = "ios")] { @@ -256,3 +309,19 @@ cfg_if::cfg_if! { extern "C" {} } } + +#[cfg(target_os = "espidf")] +mod unsupported { + use crate::io; + + pub fn unsupported<T>() -> io::Result<T> { + Err(unsupported_err()) + } + + pub fn unsupported_err() -> io::Error { + io::Error::new_const( + io::ErrorKind::Unsupported, + &"operation not supported on this platform", + ) + } +} diff --git a/library/std/src/sys/unix/net.rs b/library/std/src/sys/unix/net.rs index d5a15964c08..3f614fde08a 100644 --- a/library/std/src/sys/unix/net.rs +++ b/library/std/src/sys/unix/net.rs @@ -9,7 +9,7 @@ use crate::sys_common::net::{getsockopt, setsockopt, sockaddr_to_addr}; use crate::sys_common::{AsInner, FromInner, IntoInner}; use crate::time::{Duration, Instant}; -use libc::{c_int, c_void, size_t, sockaddr, socklen_t, EAI_SYSTEM, MSG_PEEK}; +use libc::{c_int, c_void, size_t, sockaddr, socklen_t, MSG_PEEK}; pub use crate::sys::{cvt, cvt_r}; @@ -30,15 +30,21 @@ pub fn cvt_gai(err: c_int) -> io::Result<()> { // We may need to trigger a glibc workaround. See on_resolver_failure() for details. on_resolver_failure(); - if err == EAI_SYSTEM { + #[cfg(not(target_os = "espidf"))] + if err == libc::EAI_SYSTEM { return Err(io::Error::last_os_error()); } + #[cfg(not(target_os = "espidf"))] let detail = unsafe { str::from_utf8(CStr::from_ptr(libc::gai_strerror(err)).to_bytes()).unwrap().to_owned() }; + + #[cfg(target_os = "espidf")] + let detail = ""; + Err(io::Error::new( - io::ErrorKind::Other, + io::ErrorKind::Uncategorized, &format!("failed to lookup address information: {}", detail)[..], )) } @@ -178,7 +184,7 @@ impl Socket { if pollfd.revents & libc::POLLHUP != 0 { let e = self.take_error()?.unwrap_or_else(|| { io::Error::new_const( - io::ErrorKind::Other, + io::ErrorKind::Uncategorized, &"no error set after POLLHUP", ) }); diff --git a/library/std/src/sys/unix/os.rs b/library/std/src/sys/unix/os.rs index bbc4691d963..1d5ffb07321 100644 --- a/library/std/src/sys/unix/os.rs +++ b/library/std/src/sys/unix/os.rs @@ -20,10 +20,12 @@ use crate::str; use crate::sys::cvt; use crate::sys::fd; use crate::sys::memchr; -use crate::sys::rwlock::{RWLockReadGuard, StaticRWLock}; -use crate::sys_common::mutex::{StaticMutex, StaticMutexGuard}; +use crate::sys_common::rwlock::{StaticRWLock, StaticRWLockReadGuard}; use crate::vec; +#[cfg(all(target_env = "gnu", not(target_os = "vxworks")))] +use crate::sys::weak::weak; + use libc::{c_char, c_int, c_void}; const TMPBUF_SZ: usize = 128; @@ -126,6 +128,12 @@ pub fn error_string(errno: i32) -> String { } } +#[cfg(target_os = "espidf")] +pub fn getcwd() -> io::Result<PathBuf> { + Ok(PathBuf::from("/")) +} + +#[cfg(not(target_os = "espidf"))] pub fn getcwd() -> io::Result<PathBuf> { let mut buf = Vec::with_capacity(512); loop { @@ -152,6 +160,12 @@ pub fn getcwd() -> io::Result<PathBuf> { } } +#[cfg(target_os = "espidf")] +pub fn chdir(p: &path::Path) -> io::Result<()> { + super::unsupported::unsupported() +} + +#[cfg(not(target_os = "espidf"))] pub fn chdir(p: &path::Path) -> io::Result<()> { let p: &OsStr = p.as_ref(); let p = CString::new(p.as_bytes())?; @@ -280,7 +294,7 @@ pub fn current_exe() -> io::Result<PathBuf> { ))?; if path_len <= 1 { return Err(io::Error::new_const( - io::ErrorKind::Other, + io::ErrorKind::Uncategorized, &"KERN_PROC_PATHNAME sysctl returned zero-length string", )); } @@ -303,7 +317,7 @@ pub fn current_exe() -> io::Result<PathBuf> { return crate::fs::read_link(curproc_exe); } Err(io::Error::new_const( - io::ErrorKind::Other, + io::ErrorKind::Uncategorized, &"/proc/curproc/exe doesn't point to regular file.", )) } @@ -321,7 +335,10 @@ pub fn current_exe() -> io::Result<PathBuf> { cvt(libc::sysctl(mib, 4, argv.as_mut_ptr() as *mut _, &mut argv_len, ptr::null_mut(), 0))?; argv.set_len(argv_len as usize); if argv[0].is_null() { - return Err(io::Error::new_const(io::ErrorKind::Other, &"no current exe available")); + return Err(io::Error::new_const( + io::ErrorKind::Uncategorized, + &"no current exe available", + )); } let argv0 = CStr::from_ptr(argv[0]).to_bytes(); if argv0[0] == b'.' || argv0.iter().any(|b| *b == b'/') { @@ -336,7 +353,7 @@ pub fn current_exe() -> io::Result<PathBuf> { pub fn current_exe() -> io::Result<PathBuf> { match crate::fs::read_link("/proc/self/exe") { Err(ref e) if e.kind() == io::ErrorKind::NotFound => Err(io::Error::new_const( - io::ErrorKind::Other, + io::ErrorKind::Uncategorized, &"no /proc/self/exe available. Is /proc mounted?", )), other => other, @@ -345,17 +362,14 @@ pub fn current_exe() -> io::Result<PathBuf> { #[cfg(any(target_os = "macos", target_os = "ios"))] pub fn current_exe() -> io::Result<PathBuf> { - extern "C" { - fn _NSGetExecutablePath(buf: *mut libc::c_char, bufsize: *mut u32) -> libc::c_int; - } unsafe { let mut sz: u32 = 0; - _NSGetExecutablePath(ptr::null_mut(), &mut sz); + libc::_NSGetExecutablePath(ptr::null_mut(), &mut sz); if sz == 0 { return Err(io::Error::last_os_error()); } let mut v: Vec<u8> = Vec::with_capacity(sz as usize); - let err = _NSGetExecutablePath(v.as_mut_ptr() as *mut i8, &mut sz); + let err = libc::_NSGetExecutablePath(v.as_mut_ptr() as *mut i8, &mut sz); if err != 0 { return Err(io::Error::last_os_error()); } @@ -386,46 +400,21 @@ pub fn current_exe() -> io::Result<PathBuf> { #[cfg(target_os = "haiku")] pub fn current_exe() -> io::Result<PathBuf> { - // Use Haiku's image info functions - #[repr(C)] - struct image_info { - id: i32, - type_: i32, - sequence: i32, - init_order: i32, - init_routine: *mut libc::c_void, // function pointer - term_routine: *mut libc::c_void, // function pointer - device: libc::dev_t, - node: libc::ino_t, - name: [libc::c_char; 1024], // MAXPATHLEN - text: *mut libc::c_void, - data: *mut libc::c_void, - text_size: i32, - data_size: i32, - api_version: i32, - abi: i32, - } - unsafe { - extern "C" { - fn _get_next_image_info( - team_id: i32, - cookie: *mut i32, - info: *mut image_info, - size: i32, - ) -> i32; - } - - let mut info: image_info = mem::zeroed(); + let mut info: mem::MaybeUninit<libc::image_info> = mem::MaybeUninit::uninit(); let mut cookie: i32 = 0; // the executable can be found at team id 0 - let result = - _get_next_image_info(0, &mut cookie, &mut info, mem::size_of::<image_info>() as i32); + let result = libc::_get_next_image_info( + 0, + &mut cookie, + info.as_mut_ptr(), + mem::size_of::<libc::image_info>(), + ); if result != 0 { use crate::io::ErrorKind; - Err(io::Error::new_const(ErrorKind::Other, &"Error getting executable path")) + Err(io::Error::new_const(ErrorKind::Uncategorized, &"Error getting executable path")) } else { - let name = CStr::from_ptr(info.name.as_ptr()).to_bytes(); + let name = CStr::from_ptr((*info.as_ptr()).name.as_ptr()).to_bytes(); Ok(PathBuf::from(OsStr::from_bytes(name))) } } @@ -455,6 +444,11 @@ pub fn current_exe() -> io::Result<PathBuf> { path.canonicalize() } +#[cfg(target_os = "espidf")] +pub fn current_exe() -> io::Result<PathBuf> { + super::unsupported::unsupported() +} + pub struct Env { iter: vec::IntoIter<(OsString, OsString)>, } @@ -490,8 +484,8 @@ pub unsafe fn environ() -> *mut *const *const c_char { static ENV_LOCK: StaticRWLock = StaticRWLock::new(); -pub fn env_read_lock() -> RWLockReadGuard { - ENV_LOCK.read_with_guard() +pub fn env_read_lock() -> StaticRWLockReadGuard { + ENV_LOCK.read() } /// Returns a vector of (variable, value) byte-vector pairs for all the @@ -530,19 +524,18 @@ pub fn env() -> Env { } } -pub fn getenv(k: &OsStr) -> io::Result<Option<OsString>> { +pub fn getenv(k: &OsStr) -> Option<OsString> { // environment variables with a nul byte can't be set, so their value is // always None as well - let k = CString::new(k.as_bytes())?; + let k = CString::new(k.as_bytes()).ok()?; unsafe { let _guard = env_read_lock(); let s = libc::getenv(k.as_ptr()) as *const libc::c_char; - let ret = if s.is_null() { + if s.is_null() { None } else { Some(OsStringExt::from_vec(CStr::from_ptr(s).to_bytes().to_vec())) - }; - Ok(ret) + } } } @@ -551,7 +544,7 @@ pub fn setenv(k: &OsStr, v: &OsStr) -> io::Result<()> { let v = CString::new(v.as_bytes())?; unsafe { - let _guard = ENV_LOCK.write_with_guard(); + let _guard = ENV_LOCK.write(); cvt(libc::setenv(k.as_ptr(), v.as_ptr(), 1)).map(drop) } } @@ -560,11 +553,12 @@ pub fn unsetenv(n: &OsStr) -> io::Result<()> { let nbuf = CString::new(n.as_bytes())?; unsafe { - let _guard = ENV_LOCK.write_with_guard(); + let _guard = ENV_LOCK.write(); cvt(libc::unsetenv(nbuf.as_ptr())).map(drop) } } +#[cfg(not(target_os = "espidf"))] pub fn page_size() -> usize { unsafe { libc::sysconf(libc::_SC_PAGESIZE) as usize } } @@ -587,7 +581,8 @@ pub fn home_dir() -> Option<PathBuf> { target_os = "ios", target_os = "emscripten", target_os = "redox", - target_os = "vxworks" + target_os = "vxworks", + target_os = "espidf" ))] unsafe fn fallback() -> Option<OsString> { None @@ -597,7 +592,8 @@ pub fn home_dir() -> Option<PathBuf> { target_os = "ios", target_os = "emscripten", target_os = "redox", - target_os = "vxworks" + target_os = "vxworks", + target_os = "espidf" )))] unsafe fn fallback() -> Option<OsString> { let amt = match libc::sysconf(libc::_SC_GETPW_R_SIZE_MAX) { diff --git a/library/std/src/sys/unix/os/tests.rs b/library/std/src/sys/unix/os/tests.rs index 0e1dcb390a0..c445acf2722 100644 --- a/library/std/src/sys/unix/os/tests.rs +++ b/library/std/src/sys/unix/os/tests.rs @@ -1,12 +1,14 @@ use super::*; #[test] +#[cfg(not(target_os = "vxworks"))] fn test_glibc_version() { // This mostly just tests that the weak linkage doesn't panic wildly... glibc_version(); } #[test] +#[cfg(not(target_os = "vxworks"))] fn test_parse_glibc_version() { let cases = [ ("0.0", Some((0, 0))), diff --git a/library/std/src/sys_common/os_str_bytes.rs b/library/std/src/sys/unix/os_str.rs index 32705c432fa..ae96d6b4df4 100644 --- a/library/std/src/sys_common/os_str_bytes.rs +++ b/library/std/src/sys/unix/os_str.rs @@ -2,36 +2,46 @@ //! systems: just a `Vec<u8>`/`[u8]`. use crate::borrow::Cow; -use crate::ffi::{OsStr, OsString}; use crate::fmt; +use crate::fmt::Write; use crate::mem; use crate::rc::Rc; -use crate::sealed::Sealed; use crate::str; use crate::sync::Arc; -use crate::sys_common::bytestring::debug_fmt_bytestring; -use crate::sys_common::{AsInner, FromInner, IntoInner}; +use crate::sys_common::{AsInner, IntoInner}; -use core::str::lossy::Utf8Lossy; +use core::str::lossy::{Utf8Lossy, Utf8LossyChunk}; + +#[cfg(test)] +#[path = "../unix/os_str/tests.rs"] +mod tests; #[derive(Hash)] -pub(crate) struct Buf { +#[repr(transparent)] +pub struct Buf { pub inner: Vec<u8>, } -// FIXME: -// `Buf::as_slice` current implementation relies -// on `Slice` being layout-compatible with `[u8]`. -// When attribute privacy is implemented, `Slice` should be annotated as `#[repr(transparent)]`. -// Anyway, `Slice` representation and layout are considered implementation detail, are -// not documented and must not be relied upon. -pub(crate) struct Slice { +#[repr(transparent)] +pub struct Slice { pub inner: [u8], } impl fmt::Debug for Slice { fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { - debug_fmt_bytestring(&self.inner, formatter) + // Writes out a valid unicode string with the correct escape sequences + + formatter.write_str("\"")?; + for Utf8LossyChunk { valid, broken } in Utf8Lossy::from_bytes(&self.inner).chunks() { + for c in valid.chars().flat_map(|c| c.escape_debug()) { + formatter.write_char(c)? + } + + for b in broken { + write!(formatter, "\\x{:02X}", b)?; + } + } + formatter.write_str("\"") } } @@ -243,63 +253,3 @@ impl Slice { self.inner.eq_ignore_ascii_case(&other.inner) } } - -/// Platform-specific extensions to [`OsString`]. -/// -/// This trait is sealed: it cannot be implemented outside the standard library. -/// This is so that future additional methods are not breaking changes. -#[stable(feature = "rust1", since = "1.0.0")] -pub trait OsStringExt: Sealed { - /// Creates an [`OsString`] from a byte vector. - /// - /// See the module documentation for an example. - #[stable(feature = "rust1", since = "1.0.0")] - fn from_vec(vec: Vec<u8>) -> Self; - - /// Yields the underlying byte vector of this [`OsString`]. - /// - /// See the module documentation for an example. - #[stable(feature = "rust1", since = "1.0.0")] - fn into_vec(self) -> Vec<u8>; -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl OsStringExt for OsString { - fn from_vec(vec: Vec<u8>) -> OsString { - FromInner::from_inner(Buf { inner: vec }) - } - fn into_vec(self) -> Vec<u8> { - self.into_inner().inner - } -} - -/// Platform-specific extensions to [`OsStr`]. -/// -/// This trait is sealed: it cannot be implemented outside the standard library. -/// This is so that future additional methods are not breaking changes. -#[stable(feature = "rust1", since = "1.0.0")] -pub trait OsStrExt: Sealed { - #[stable(feature = "rust1", since = "1.0.0")] - /// Creates an [`OsStr`] from a byte slice. - /// - /// See the module documentation for an example. - fn from_bytes(slice: &[u8]) -> &Self; - - /// Gets the underlying byte view of the [`OsStr`] slice. - /// - /// See the module documentation for an example. - #[stable(feature = "rust1", since = "1.0.0")] - fn as_bytes(&self) -> &[u8]; -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl OsStrExt for OsStr { - #[inline] - fn from_bytes(slice: &[u8]) -> &OsStr { - unsafe { mem::transmute(slice) } - } - #[inline] - fn as_bytes(&self) -> &[u8] { - &self.as_inner().inner - } -} diff --git a/library/std/src/sys/unix/os_str/tests.rs b/library/std/src/sys/unix/os_str/tests.rs new file mode 100644 index 00000000000..37967378155 --- /dev/null +++ b/library/std/src/sys/unix/os_str/tests.rs @@ -0,0 +1,10 @@ +use super::*; + +#[test] +fn slice_debug_output() { + let input = Slice::from_u8_slice(b"\xF0hello,\tworld"); + let expected = r#""\xF0hello,\tworld""#; + let output = format!("{:?}", input); + + assert_eq!(output, expected); +} diff --git a/library/std/src/sys/unix/process/mod.rs b/library/std/src/sys/unix/process/mod.rs index b5a19ed54a2..0165ece849e 100644 --- a/library/std/src/sys/unix/process/mod.rs +++ b/library/std/src/sys/unix/process/mod.rs @@ -13,6 +13,9 @@ cfg_if::cfg_if! { } else if #[cfg(target_os = "vxworks")] { #[path = "process_vxworks.rs"] mod process_inner; + } else if #[cfg(target_os = "espidf")] { + #[path = "process_unsupported.rs"] + mod process_inner; } else { #[path = "process_unix.rs"] mod process_inner; diff --git a/library/std/src/sys/unix/process/process_common.rs b/library/std/src/sys/unix/process/process_common.rs index c5bdd1bda4a..a1972380a9f 100644 --- a/library/std/src/sys/unix/process/process_common.rs +++ b/library/std/src/sys/unix/process/process_common.rs @@ -50,7 +50,7 @@ cfg_if::cfg_if! { raw[bit / 8] |= 1 << (bit % 8); return 0; } - } else if #[cfg(not(target_os = "vxworks"))] { + } else { pub use libc::{sigemptyset, sigaddset}; } } @@ -79,6 +79,8 @@ pub struct Command { stdin: Option<Stdio>, stdout: Option<Stdio>, stderr: Option<Stdio>, + #[cfg(target_os = "linux")] + create_pidfd: bool, } // Create a new type for argv, so that we can make it `Send` and `Sync` @@ -124,6 +126,28 @@ pub enum Stdio { } impl Command { + #[cfg(not(target_os = "linux"))] + pub fn new(program: &OsStr) -> Command { + let mut saw_nul = false; + let program = os2c(program, &mut saw_nul); + Command { + argv: Argv(vec![program.as_ptr(), ptr::null()]), + args: vec![program.clone()], + program, + env: Default::default(), + cwd: None, + uid: None, + gid: None, + saw_nul, + closures: Vec::new(), + groups: None, + stdin: None, + stdout: None, + stderr: None, + } + } + + #[cfg(target_os = "linux")] pub fn new(program: &OsStr) -> Command { let mut saw_nul = false; let program = os2c(program, &mut saw_nul); @@ -141,6 +165,7 @@ impl Command { stdin: None, stdout: None, stderr: None, + create_pidfd: false, } } @@ -177,6 +202,22 @@ impl Command { self.groups = Some(Box::from(groups)); } + #[cfg(target_os = "linux")] + pub fn create_pidfd(&mut self, val: bool) { + self.create_pidfd = val; + } + + #[cfg(not(target_os = "linux"))] + #[allow(dead_code)] + pub fn get_create_pidfd(&self) -> bool { + false + } + + #[cfg(target_os = "linux")] + pub fn get_create_pidfd(&self) -> bool { + self.create_pidfd + } + pub fn saw_nul(&self) -> bool { self.saw_nul } diff --git a/library/std/src/sys/unix/process/process_unix.rs b/library/std/src/sys/unix/process/process_unix.rs index ed55e1aa715..4b210d6af13 100644 --- a/library/std/src/sys/unix/process/process_unix.rs +++ b/library/std/src/sys/unix/process/process_unix.rs @@ -9,6 +9,20 @@ use crate::sys; use crate::sys::cvt; use crate::sys::process::process_common::*; +#[cfg(target_os = "linux")] +use crate::os::linux::process::PidFd; + +#[cfg(target_os = "linux")] +use crate::sys::weak::syscall; + +#[cfg(any( + target_os = "macos", + target_os = "freebsd", + all(target_os = "linux", target_env = "gnu"), + all(target_os = "linux", target_env = "musl"), +))] +use crate::sys::weak::weak; + #[cfg(target_os = "vxworks")] use libc::RTP_ID as pid_t; @@ -53,7 +67,8 @@ impl Command { // a lock any more because the parent won't do anything and the child is // in its own process. Thus the parent drops the lock guard while the child // forgets it to avoid unlocking it on a new thread, which would be invalid. - let (env_lock, pid) = unsafe { (sys::os::env_read_lock(), cvt(libc::fork())?) }; + let env_lock = sys::os::env_read_lock(); + let (pid, pidfd) = unsafe { self.do_fork()? }; if pid == 0 { crate::panic::always_abort(); @@ -82,7 +97,7 @@ impl Command { drop(env_lock); drop(output); - let mut p = Process { pid, status: None }; + let mut p = Process::new(pid, pidfd); let mut bytes = [0; 8]; // loop to handle EINTR @@ -114,6 +129,92 @@ impl Command { } } + // Attempts to fork the process. If successful, returns Ok((0, -1)) + // in the child, and Ok((child_pid, -1)) in the parent. + #[cfg(not(target_os = "linux"))] + unsafe fn do_fork(&mut self) -> Result<(pid_t, pid_t), io::Error> { + cvt(libc::fork()).map(|res| (res, -1)) + } + + // Attempts to fork the process. If successful, returns Ok((0, -1)) + // in the child, and Ok((child_pid, child_pidfd)) in the parent. + #[cfg(target_os = "linux")] + unsafe fn do_fork(&mut self) -> Result<(pid_t, pid_t), io::Error> { + use crate::sync::atomic::{AtomicBool, Ordering}; + + static HAS_CLONE3: AtomicBool = AtomicBool::new(true); + const CLONE_PIDFD: u64 = 0x00001000; + + #[repr(C)] + struct clone_args { + flags: u64, + pidfd: u64, + child_tid: u64, + parent_tid: u64, + exit_signal: u64, + stack: u64, + stack_size: u64, + tls: u64, + set_tid: u64, + set_tid_size: u64, + cgroup: u64, + } + + syscall! { + fn clone3(cl_args: *mut clone_args, len: libc::size_t) -> libc::c_long + } + + // If we fail to create a pidfd for any reason, this will + // stay as -1, which indicates an error. + let mut pidfd: pid_t = -1; + + // Attempt to use the `clone3` syscall, which supports more arguments + // (in particular, the ability to create a pidfd). If this fails, + // we will fall through this block to a call to `fork()` + if HAS_CLONE3.load(Ordering::Relaxed) { + let mut flags = 0; + if self.get_create_pidfd() { + flags |= CLONE_PIDFD; + } + + let mut args = clone_args { + flags, + pidfd: &mut pidfd as *mut pid_t as u64, + child_tid: 0, + parent_tid: 0, + exit_signal: libc::SIGCHLD as u64, + stack: 0, + stack_size: 0, + tls: 0, + set_tid: 0, + set_tid_size: 0, + cgroup: 0, + }; + + let args_ptr = &mut args as *mut clone_args; + let args_size = crate::mem::size_of::<clone_args>(); + + let res = cvt(clone3(args_ptr, args_size)); + match res { + Ok(n) => return Ok((n as pid_t, pidfd)), + Err(e) => match e.raw_os_error() { + // Multiple threads can race to execute this store, + // but that's fine - that just means that multiple threads + // will have tried and failed to execute the same syscall, + // with no other side effects. + Some(libc::ENOSYS) => HAS_CLONE3.store(false, Ordering::Relaxed), + // Fallback to fork if `EPERM` is returned. (e.g. blocked by seccomp) + Some(libc::EPERM) => {} + _ => return Err(e), + }, + } + } + + // If we get here, the 'clone3' syscall does not exist + // or we do not have permission to call it + cvt(libc::fork()).map(|res| (res, pidfd)) + } + pub fn exec(&mut self, default: Stdio) -> io::Error { let envp = self.capture_env(); @@ -300,6 +401,7 @@ impl Command { || (self.env_saw_path() && !self.program_is_path()) || !self.get_closures().is_empty() || self.get_groups().is_some() + || self.get_create_pidfd() { return Ok(None); } @@ -344,7 +446,7 @@ impl Command { None => None, }; - let mut p = Process { pid: 0, status: None }; + let mut p = Process::new(0, -1); struct PosixSpawnFileActions<'a>(&'a mut MaybeUninit<libc::posix_spawn_file_actions_t>); @@ -433,9 +535,27 @@ impl Command { pub struct Process { pid: pid_t, status: Option<ExitStatus>, + // On Linux, stores the pidfd created for this child. + // This is None if the user did not request pidfd creation, + // or if the pidfd could not be created for some reason + // (e.g. the `clone3` syscall was not available). + #[cfg(target_os = "linux")] + pidfd: Option<PidFd>, } impl Process { + #[cfg(target_os = "linux")] + fn new(pid: pid_t, pidfd: pid_t) -> Self { + use crate::sys_common::FromInner; + let pidfd = (pidfd >= 0).then(|| PidFd::from_inner(sys::fd::FileDesc::new(pidfd))); + Process { pid, status: None, pidfd } + } + + #[cfg(not(target_os = "linux"))] + fn new(pid: pid_t, _pidfd: pid_t) -> Self { + Process { pid, status: None } + } + pub fn id(&self) -> u32 { self.pid as u32 } @@ -572,6 +692,24 @@ impl ExitStatusError { } } +#[cfg(target_os = "linux")] +#[unstable(feature = "linux_pidfd", issue = "82971")] +impl crate::os::linux::process::ChildExt for crate::process::Child { + fn pidfd(&self) -> io::Result<&PidFd> { + self.handle + .pidfd + .as_ref() + .ok_or_else(|| Error::new(ErrorKind::Other, "No pidfd was created.")) + } + + fn take_pidfd(&mut self) -> io::Result<PidFd> { + self.handle + .pidfd + .take() + .ok_or_else(|| Error::new(ErrorKind::Other, "No pidfd was created.")) + } +} + #[cfg(test)] #[path = "process_unix/tests.rs"] mod tests; diff --git a/library/std/src/sys/unix/process/process_unsupported.rs b/library/std/src/sys/unix/process/process_unsupported.rs new file mode 100644 index 00000000000..7d549d060fd --- /dev/null +++ b/library/std/src/sys/unix/process/process_unsupported.rs @@ -0,0 +1,122 @@ +use crate::convert::{TryFrom, TryInto}; +use crate::fmt; +use crate::io; +use crate::io::ErrorKind; +use crate::num::NonZeroI32; +use crate::os::raw::NonZero_c_int; +use crate::sys; +use crate::sys::cvt; +use crate::sys::pipe::AnonPipe; +use crate::sys::process::process_common::*; +use crate::sys::unix::unsupported::*; + +use libc::{c_int, pid_t}; + +//////////////////////////////////////////////////////////////////////////////// +// Command +//////////////////////////////////////////////////////////////////////////////// + +impl Command { + pub fn spawn( + &mut self, + default: Stdio, + needs_stdin: bool, + ) -> io::Result<(Process, StdioPipes)> { + unsupported() + } + + pub fn exec(&mut self, default: Stdio) -> io::Error { + unsupported_err() + } +} + +//////////////////////////////////////////////////////////////////////////////// +// Processes +//////////////////////////////////////////////////////////////////////////////// + +pub struct Process { + handle: pid_t, +} + +impl Process { + pub fn id(&self) -> u32 { + 0 + } + + pub fn kill(&mut self) -> io::Result<()> { + unsupported() + } + + pub fn wait(&mut self) -> io::Result<ExitStatus> { + unsupported() + } + + pub fn try_wait(&mut self) -> io::Result<Option<ExitStatus>> { + unsupported() + } +} + +#[derive(PartialEq, Eq, Clone, Copy, Debug)] +pub struct ExitStatus(c_int); + +impl ExitStatus { + pub fn success(&self) -> bool { + self.code() == Some(0) + } + + pub fn exit_ok(&self) -> Result<(), ExitStatusError> { + Err(ExitStatusError(1.try_into().unwrap())) + } + + pub fn code(&self) -> Option<i32> { + None + } + + pub fn signal(&self) -> Option<i32> { + None + } + + pub fn core_dumped(&self) -> bool { + false + } + + pub fn stopped_signal(&self) -> Option<i32> { + None + } + + pub fn continued(&self) -> bool { + false + } + + pub fn into_raw(&self) -> c_int { + 0 + } +} + +/// Converts a raw `c_int` to a type-safe `ExitStatus` by wrapping it without copying. +impl From<c_int> for ExitStatus { + fn from(a: c_int) -> ExitStatus { + ExitStatus(a as i32) + } +} + +impl fmt::Display for ExitStatus { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "exit code: {}", self.0) + } +} + +#[derive(PartialEq, Eq, Clone, Copy, Debug)] +pub struct ExitStatusError(NonZero_c_int); + +impl Into<ExitStatus> for ExitStatusError { + fn into(self) -> ExitStatus { + ExitStatus(self.0.into()) + } +} + +impl ExitStatusError { + pub fn code(self) -> Option<NonZeroI32> { + ExitStatus(self.0.into()).code().map(|st| st.try_into().unwrap()) + } +} diff --git a/library/std/src/sys/unix/rand.rs b/library/std/src/sys/unix/rand.rs index 44f9eabc319..7a3f6b0d95a 100644 --- a/library/std/src/sys/unix/rand.rs +++ b/library/std/src/sys/unix/rand.rs @@ -26,6 +26,9 @@ mod imp { use crate::io::Read; #[cfg(any(target_os = "linux", target_os = "android"))] + use crate::sys::weak::syscall; + + #[cfg(any(target_os = "linux", target_os = "android"))] fn getrandom(buf: &mut [u8]) -> libc::ssize_t { // A weak symbol allows interposition, e.g. for perf measurements that want to // disable randomness for consistency. Otherwise, we'll try a raw syscall. @@ -41,12 +44,17 @@ mod imp { unsafe { getrandom(buf.as_mut_ptr().cast(), buf.len(), libc::GRND_NONBLOCK) } } - #[cfg(not(any(target_os = "linux", target_os = "android")))] + #[cfg(target_os = "espidf")] + fn getrandom(buf: &mut [u8]) -> libc::ssize_t { + unsafe { libc::getrandom(buf.as_mut_ptr().cast(), buf.len(), 0) } + } + + #[cfg(not(any(target_os = "linux", target_os = "android", target_os = "espidf")))] fn getrandom_fill_bytes(_buf: &mut [u8]) -> bool { false } - #[cfg(any(target_os = "linux", target_os = "android"))] + #[cfg(any(target_os = "linux", target_os = "android", target_os = "espidf"))] fn getrandom_fill_bytes(v: &mut [u8]) -> bool { use crate::sync::atomic::{AtomicBool, Ordering}; use crate::sys::os::errno; @@ -108,6 +116,7 @@ mod imp { use crate::fs::File; use crate::io::Read; use crate::sys::os::errno; + use crate::sys::weak::weak; use libc::{c_int, c_void, size_t}; fn getentropy_fill_bytes(v: &mut [u8]) -> bool { diff --git a/library/std/src/sys/unix/rwlock.rs b/library/std/src/sys/unix/rwlock.rs index d97d9d712fc..b1faf12c226 100644 --- a/library/std/src/sys/unix/rwlock.rs +++ b/library/std/src/sys/unix/rwlock.rs @@ -7,6 +7,8 @@ pub struct RWLock { num_readers: AtomicUsize, } +pub type MovableRWLock = Box<RWLock>; + unsafe impl Send for RWLock {} unsafe impl Sync for RWLock {} @@ -139,55 +141,3 @@ impl RWLock { } } } - -pub struct StaticRWLock(RWLock); - -impl StaticRWLock { - pub const fn new() -> StaticRWLock { - StaticRWLock(RWLock::new()) - } - - /// Acquires shared access to the underlying lock, blocking the current - /// thread to do so. - /// - /// The lock is automatically unlocked when the returned guard is dropped. - #[inline] - pub fn read_with_guard(&'static self) -> RWLockReadGuard { - // SAFETY: All methods require static references, therefore self - // cannot be moved between invocations. - unsafe { - self.0.read(); - } - RWLockReadGuard(&self.0) - } - - /// Acquires write access to the underlying lock, blocking the current thread - /// to do so. - /// - /// The lock is automatically unlocked when the returned guard is dropped. - #[inline] - pub fn write_with_guard(&'static self) -> RWLockWriteGuard { - // SAFETY: All methods require static references, therefore self - // cannot be moved between invocations. - unsafe { - self.0.write(); - } - RWLockWriteGuard(&self.0) - } -} - -pub struct RWLockReadGuard(&'static RWLock); - -impl Drop for RWLockReadGuard { - fn drop(&mut self) { - unsafe { self.0.read_unlock() } - } -} - -pub struct RWLockWriteGuard(&'static RWLock); - -impl Drop for RWLockWriteGuard { - fn drop(&mut self) { - unsafe { self.0.write_unlock() } - } -} diff --git a/library/std/src/sys/unix/thread.rs b/library/std/src/sys/unix/thread.rs index b8f43caec32..133ad3ea420 100644 --- a/library/std/src/sys/unix/thread.rs +++ b/library/std/src/sys/unix/thread.rs @@ -2,16 +2,38 @@ use crate::cmp; use crate::ffi::CStr; use crate::io; use crate::mem; +use crate::num::NonZeroUsize; use crate::ptr; use crate::sys::{os, stack_overflow}; use crate::time::Duration; -#[cfg(not(any(target_os = "l4re", target_os = "vxworks")))] +#[cfg(any(target_os = "linux", target_os = "solaris", target_os = "illumos"))] +use crate::sys::weak::weak; +#[cfg(not(any(target_os = "l4re", target_os = "vxworks", target_os = "espidf")))] pub const DEFAULT_MIN_STACK_SIZE: usize = 2 * 1024 * 1024; #[cfg(target_os = "l4re")] pub const DEFAULT_MIN_STACK_SIZE: usize = 1024 * 1024; #[cfg(target_os = "vxworks")] pub const DEFAULT_MIN_STACK_SIZE: usize = 256 * 1024; +#[cfg(target_os = "espidf")] +pub const DEFAULT_MIN_STACK_SIZE: usize = 0; // 0 indicates that the stack size configured in the ESP-IDF menuconfig system should be used + +#[cfg(target_os = "fuchsia")] +mod zircon { + type zx_handle_t = u32; + type zx_status_t = i32; + pub const ZX_PROP_NAME: u32 = 3; + + extern "C" { + pub fn zx_object_set_property( + handle: zx_handle_t, + property: u32, + value: *const libc::c_void, + value_size: libc::size_t, + ) -> zx_status_t; + pub fn zx_thread_self() -> zx_handle_t; + } +} pub struct Thread { id: libc::pthread_t, @@ -30,22 +52,35 @@ impl Thread { let mut attr: libc::pthread_attr_t = mem::zeroed(); assert_eq!(libc::pthread_attr_init(&mut attr), 0); - let stack_size = cmp::max(stack, min_stack_size(&attr)); - - match libc::pthread_attr_setstacksize(&mut attr, stack_size) { - 0 => {} - n => { - assert_eq!(n, libc::EINVAL); - // EINVAL means |stack_size| is either too small or not a - // multiple of the system page size. Because it's definitely - // >= PTHREAD_STACK_MIN, it must be an alignment issue. - // Round up to the nearest page and try again. - let page_size = os::page_size(); - let stack_size = - (stack_size + page_size - 1) & (-(page_size as isize - 1) as usize - 1); - assert_eq!(libc::pthread_attr_setstacksize(&mut attr, stack_size), 0); - } - }; + #[cfg(target_os = "espidf")] + if stack > 0 { + // Only set the stack if a non-zero value is passed + // 0 is used as an indication that the default stack size configured in the ESP-IDF menuconfig system should be used + assert_eq!( + libc::pthread_attr_setstacksize(&mut attr, cmp::max(stack, min_stack_size(&attr))), + 0 + ); + } + + #[cfg(not(target_os = "espidf"))] + { + let stack_size = cmp::max(stack, min_stack_size(&attr)); + + match libc::pthread_attr_setstacksize(&mut attr, stack_size) { + 0 => {} + n => { + assert_eq!(n, libc::EINVAL); + // EINVAL means |stack_size| is either too small or not a + // multiple of the system page size. Because it's definitely + // >= PTHREAD_STACK_MIN, it must be an alignment issue. + // Round up to the nearest page and try again. + let page_size = os::page_size(); + let stack_size = + (stack_size + page_size - 1) & (-(page_size as isize - 1) as usize - 1); + assert_eq!(libc::pthread_attr_setstacksize(&mut attr, stack_size), 0); + } + }; + } let ret = libc::pthread_create(&mut native, &attr, thread_start, p as *mut _); // Note: if the thread creation fails and this assert fails, then p will @@ -131,22 +166,39 @@ impl Thread { } } + #[cfg(target_os = "fuchsia")] + pub fn set_name(name: &CStr) { + use self::zircon::*; + unsafe { + zx_object_set_property( + zx_thread_self(), + ZX_PROP_NAME, + name.as_ptr() as *const libc::c_void, + name.to_bytes().len(), + ); + } + } + + #[cfg(target_os = "haiku")] + pub fn set_name(name: &CStr) { + unsafe { + let thread_self = libc::find_thread(ptr::null_mut()); + libc::rename_thread(thread_self, name.as_ptr()); + } + } + #[cfg(any( target_env = "newlib", - target_os = "haiku", target_os = "l4re", target_os = "emscripten", target_os = "redox", target_os = "vxworks" ))] pub fn set_name(_name: &CStr) { - // Newlib, Haiku, Emscripten, and VxWorks have no way to set a thread name. - } - #[cfg(target_os = "fuchsia")] - pub fn set_name(_name: &CStr) { - // FIXME: determine whether Fuchsia has a way to set a thread name. + // Newlib, Emscripten, and VxWorks have no way to set a thread name. } + #[cfg(not(target_os = "espidf"))] pub fn sleep(dur: Duration) { let mut secs = dur.as_secs(); let mut nsecs = dur.subsec_nanos() as _; @@ -172,6 +224,19 @@ impl Thread { } } + #[cfg(target_os = "espidf")] + pub fn sleep(dur: Duration) { + let mut micros = dur.as_micros(); + unsafe { + while micros > 0 { + let st = if micros > u32::MAX as u128 { u32::MAX } else { micros as u32 }; + libc::usleep(st); + + micros -= st as u128; + } + } + } + pub fn join(self) { unsafe { let ret = libc::pthread_join(self.id, ptr::null_mut()); @@ -198,6 +263,88 @@ impl Drop for Thread { } } +pub fn available_concurrency() -> io::Result<NonZeroUsize> { + cfg_if::cfg_if! { + if #[cfg(any( + target_os = "android", + target_os = "emscripten", + target_os = "fuchsia", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "solaris", + target_os = "illumos", + ))] { + match unsafe { libc::sysconf(libc::_SC_NPROCESSORS_ONLN) } { + -1 => Err(io::Error::last_os_error()), + 0 => Err(io::Error::new_const(io::ErrorKind::NotFound, &"The number of hardware threads is not known for the target platform")), + cpus => Ok(unsafe { NonZeroUsize::new_unchecked(cpus as usize) }), + } + } else if #[cfg(any(target_os = "freebsd", target_os = "dragonfly", target_os = "netbsd"))] { + use crate::ptr; + + let mut cpus: libc::c_uint = 0; + let mut cpus_size = crate::mem::size_of_val(&cpus); + + unsafe { + cpus = libc::sysconf(libc::_SC_NPROCESSORS_ONLN) as libc::c_uint; + } + + // Fallback approach in case of errors or no hardware threads. + if cpus < 1 { + let mut mib = [libc::CTL_HW, libc::HW_NCPU, 0, 0]; + let res = unsafe { + libc::sysctl( + mib.as_mut_ptr(), + 2, + &mut cpus as *mut _ as *mut _, + &mut cpus_size as *mut _ as *mut _, + ptr::null_mut(), + 0, + ) + }; + + // Handle errors if any. + if res == -1 { + return Err(io::Error::last_os_error()); + } else if cpus == 0 { + return Err(io::Error::new_const(io::ErrorKind::NotFound, &"The number of hardware threads is not known for the target platform")); + } + } + Ok(unsafe { NonZeroUsize::new_unchecked(cpus as usize) }) + } else if #[cfg(target_os = "openbsd")] { + use crate::ptr; + + let mut cpus: libc::c_uint = 0; + let mut cpus_size = crate::mem::size_of_val(&cpus); + let mut mib = [libc::CTL_HW, libc::HW_NCPU, 0, 0]; + + let res = unsafe { + libc::sysctl( + mib.as_mut_ptr(), + 2, + &mut cpus as *mut _ as *mut _, + &mut cpus_size as *mut _ as *mut _, + ptr::null_mut(), + 0, + ) + }; + + // Handle errors if any. + if res == -1 { + return Err(io::Error::last_os_error()); + } else if cpus == 0 { + return Err(io::Error::new_const(io::ErrorKind::NotFound, &"The number of hardware threads is not known for the target platform")); + } + + Ok(unsafe { NonZeroUsize::new_unchecked(cpus as usize) }) + } else { + // FIXME: implement on vxWorks, Redox, Haiku, l4re + Err(io::Error::new_const(io::ErrorKind::Unsupported, &"Getting the number of hardware threads is not supported on the target platform")) + } + } +} + #[cfg(all( not(target_os = "linux"), not(target_os = "freebsd"), diff --git a/library/std/src/sys/unix/time.rs b/library/std/src/sys/unix/time.rs index 23a5c81c005..7dc09add27f 100644 --- a/library/std/src/sys/unix/time.rs +++ b/library/std/src/sys/unix/time.rs @@ -361,9 +361,9 @@ mod inner { } } - #[cfg(not(target_os = "dragonfly"))] + #[cfg(not(any(target_os = "dragonfly", target_os = "espidf")))] pub type clock_t = libc::c_int; - #[cfg(target_os = "dragonfly")] + #[cfg(any(target_os = "dragonfly", target_os = "espidf"))] pub type clock_t = libc::c_ulong; fn now(clock: clock_t) -> Timespec { diff --git a/library/std/src/sys/unix/weak.rs b/library/std/src/sys/unix/weak.rs index 432fe4c33bc..ba432ec5494 100644 --- a/library/std/src/sys/unix/weak.rs +++ b/library/std/src/sys/unix/weak.rs @@ -26,8 +26,9 @@ use crate::marker; use crate::mem; use crate::sync::atomic::{self, AtomicUsize, Ordering}; -macro_rules! weak { +pub(crate) macro weak { (fn $name:ident($($t:ty),*) -> $ret:ty) => ( + #[allow(non_upper_case_globals)] static $name: crate::sys::weak::Weak<unsafe extern "C" fn($($t),*) -> $ret> = crate::sys::weak::Weak::new(concat!(stringify!($name), '\0')); ) @@ -101,7 +102,7 @@ unsafe fn fetch(name: &str) -> usize { } #[cfg(not(any(target_os = "linux", target_os = "android")))] -macro_rules! syscall { +pub(crate) macro syscall { (fn $name:ident($($arg_name:ident: $t:ty),*) -> $ret:ty) => ( unsafe fn $name($($arg_name: $t),*) -> $ret { use super::os; @@ -119,9 +120,10 @@ macro_rules! syscall { } #[cfg(any(target_os = "linux", target_os = "android"))] -macro_rules! syscall { +pub(crate) macro syscall { (fn $name:ident($($arg_name:ident: $t:ty),*) -> $ret:ty) => ( unsafe fn $name($($arg_name:$t),*) -> $ret { + use weak; // This looks like a hack, but concat_idents only accepts idents // (not paths). use libc::*; diff --git a/library/std/src/sys/unsupported/common.rs b/library/std/src/sys/unsupported/common.rs index 6e72a7c632e..a06b44e96a9 100644 --- a/library/std/src/sys/unsupported/common.rs +++ b/library/std/src/sys/unsupported/common.rs @@ -4,8 +4,6 @@ pub mod memchr { pub use core::slice::memchr::{memchr, memrchr}; } -pub use crate::sys_common::os_str_bytes as os_str; - // This is not necessarily correct. May want to consider making it part of the // spec definition? use crate::os::raw::c_char; @@ -30,7 +28,7 @@ pub fn unsupported_err() -> std_io::Error { } pub fn decode_error_kind(_code: i32) -> crate::io::ErrorKind { - crate::io::ErrorKind::Other + crate::io::ErrorKind::Uncategorized } pub fn abort_internal() -> ! { diff --git a/library/std/src/sys/unsupported/mod.rs b/library/std/src/sys/unsupported/mod.rs index 3ef4c6b8a8f..a1276193bda 100644 --- a/library/std/src/sys/unsupported/mod.rs +++ b/library/std/src/sys/unsupported/mod.rs @@ -11,6 +11,8 @@ pub mod io; pub mod mutex; pub mod net; pub mod os; +#[path = "../unix/os_str.rs"] +pub mod os_str; #[path = "../unix/path.rs"] pub mod path; pub mod pipe; diff --git a/library/std/src/sys/unsupported/os.rs b/library/std/src/sys/unsupported/os.rs index e30395a0b1d..2886ec1180e 100644 --- a/library/std/src/sys/unsupported/os.rs +++ b/library/std/src/sys/unsupported/os.rs @@ -76,8 +76,8 @@ pub fn env() -> Env { panic!("not supported on this platform") } -pub fn getenv(_: &OsStr) -> io::Result<Option<OsString>> { - Ok(None) +pub fn getenv(_: &OsStr) -> Option<OsString> { + None } pub fn setenv(_: &OsStr, _: &OsStr) -> io::Result<()> { diff --git a/library/std/src/sys/unsupported/rwlock.rs b/library/std/src/sys/unsupported/rwlock.rs index 6982b2b155f..8438adeb5b5 100644 --- a/library/std/src/sys/unsupported/rwlock.rs +++ b/library/std/src/sys/unsupported/rwlock.rs @@ -5,6 +5,8 @@ pub struct RWLock { mode: Cell<isize>, } +pub type MovableRWLock = RWLock; + unsafe impl Send for RWLock {} unsafe impl Sync for RWLock {} // no threads on this platform diff --git a/library/std/src/sys/unsupported/thread.rs b/library/std/src/sys/unsupported/thread.rs index cda8510e1ba..dc75d4ee672 100644 --- a/library/std/src/sys/unsupported/thread.rs +++ b/library/std/src/sys/unsupported/thread.rs @@ -1,6 +1,7 @@ use super::unsupported; use crate::ffi::CStr; use crate::io; +use crate::num::NonZeroUsize; use crate::time::Duration; pub struct Thread(!); @@ -30,6 +31,10 @@ impl Thread { } } +pub fn available_concurrency() -> io::Result<NonZeroUsize> { + unsupported() +} + pub mod guard { pub type Guard = !; pub unsafe fn current() -> Option<Guard> { diff --git a/library/std/src/sys/wasi/fd.rs b/library/std/src/sys/wasi/fd.rs index ba66eba2ad3..1f6ea8d6e8d 100644 --- a/library/std/src/sys/wasi/fd.rs +++ b/library/std/src/sys/wasi/fd.rs @@ -5,10 +5,11 @@ use super::err2io; use crate::io::{self, IoSlice, IoSliceMut, SeekFrom}; use crate::mem; use crate::net::Shutdown; +use crate::os::raw::c_int; #[derive(Debug)] pub struct WasiFd { - fd: wasi::Fd, + fd: c_int, } fn iovec<'a>(a: &'a mut [IoSliceMut<'_>]) -> &'a [wasi::Iovec] { @@ -26,38 +27,38 @@ fn ciovec<'a>(a: &'a [IoSlice<'_>]) -> &'a [wasi::Ciovec] { } impl WasiFd { - pub unsafe fn from_raw(fd: wasi::Fd) -> WasiFd { + pub unsafe fn from_raw(fd: c_int) -> WasiFd { WasiFd { fd } } - pub fn into_raw(self) -> wasi::Fd { + pub fn into_raw(self) -> c_int { let ret = self.fd; mem::forget(self); ret } - pub fn as_raw(&self) -> wasi::Fd { + pub fn as_raw(&self) -> c_int { self.fd } pub fn datasync(&self) -> io::Result<()> { - unsafe { wasi::fd_datasync(self.fd).map_err(err2io) } + unsafe { wasi::fd_datasync(self.fd as wasi::Fd).map_err(err2io) } } pub fn pread(&self, bufs: &mut [IoSliceMut<'_>], offset: u64) -> io::Result<usize> { - unsafe { wasi::fd_pread(self.fd, iovec(bufs), offset).map_err(err2io) } + unsafe { wasi::fd_pread(self.fd as wasi::Fd, iovec(bufs), offset).map_err(err2io) } } pub fn pwrite(&self, bufs: &[IoSlice<'_>], offset: u64) -> io::Result<usize> { - unsafe { wasi::fd_pwrite(self.fd, ciovec(bufs), offset).map_err(err2io) } + unsafe { wasi::fd_pwrite(self.fd as wasi::Fd, ciovec(bufs), offset).map_err(err2io) } } pub fn read(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> { - unsafe { wasi::fd_read(self.fd, iovec(bufs)).map_err(err2io) } + unsafe { wasi::fd_read(self.fd as wasi::Fd, iovec(bufs)).map_err(err2io) } } pub fn write(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> { - unsafe { wasi::fd_write(self.fd, ciovec(bufs)).map_err(err2io) } + unsafe { wasi::fd_write(self.fd as wasi::Fd, ciovec(bufs)).map_err(err2io) } } pub fn seek(&self, pos: SeekFrom) -> io::Result<u64> { @@ -66,37 +67,37 @@ impl WasiFd { SeekFrom::End(pos) => (wasi::WHENCE_END, pos), SeekFrom::Current(pos) => (wasi::WHENCE_CUR, pos), }; - unsafe { wasi::fd_seek(self.fd, offset, whence).map_err(err2io) } + unsafe { wasi::fd_seek(self.fd as wasi::Fd, offset, whence).map_err(err2io) } } pub fn tell(&self) -> io::Result<u64> { - unsafe { wasi::fd_tell(self.fd).map_err(err2io) } + unsafe { wasi::fd_tell(self.fd as wasi::Fd).map_err(err2io) } } // FIXME: __wasi_fd_fdstat_get pub fn set_flags(&self, flags: wasi::Fdflags) -> io::Result<()> { - unsafe { wasi::fd_fdstat_set_flags(self.fd, flags).map_err(err2io) } + unsafe { wasi::fd_fdstat_set_flags(self.fd as wasi::Fd, flags).map_err(err2io) } } pub fn set_rights(&self, base: wasi::Rights, inheriting: wasi::Rights) -> io::Result<()> { - unsafe { wasi::fd_fdstat_set_rights(self.fd, base, inheriting).map_err(err2io) } + unsafe { wasi::fd_fdstat_set_rights(self.fd as wasi::Fd, base, inheriting).map_err(err2io) } } pub fn sync(&self) -> io::Result<()> { - unsafe { wasi::fd_sync(self.fd).map_err(err2io) } + unsafe { wasi::fd_sync(self.fd as wasi::Fd).map_err(err2io) } } pub fn advise(&self, offset: u64, len: u64, advice: wasi::Advice) -> io::Result<()> { - unsafe { wasi::fd_advise(self.fd, offset, len, advice).map_err(err2io) } + unsafe { wasi::fd_advise(self.fd as wasi::Fd, offset, len, advice).map_err(err2io) } } pub fn allocate(&self, offset: u64, len: u64) -> io::Result<()> { - unsafe { wasi::fd_allocate(self.fd, offset, len).map_err(err2io) } + unsafe { wasi::fd_allocate(self.fd as wasi::Fd, offset, len).map_err(err2io) } } pub fn create_directory(&self, path: &str) -> io::Result<()> { - unsafe { wasi::path_create_directory(self.fd, path).map_err(err2io) } + unsafe { wasi::path_create_directory(self.fd as wasi::Fd, path).map_err(err2io) } } pub fn link( @@ -107,7 +108,14 @@ impl WasiFd { new_path: &str, ) -> io::Result<()> { unsafe { - wasi::path_link(self.fd, old_flags, old_path, new_fd.fd, new_path).map_err(err2io) + wasi::path_link( + self.fd as wasi::Fd, + old_flags, + old_path, + new_fd.fd as wasi::Fd, + new_path, + ) + .map_err(err2io) } } @@ -122,7 +130,7 @@ impl WasiFd { ) -> io::Result<WasiFd> { unsafe { wasi::path_open( - self.fd, + self.fd as wasi::Fd, dirflags, path, oflags, @@ -130,25 +138,34 @@ impl WasiFd { fs_rights_inheriting, fs_flags, ) - .map(|fd| WasiFd::from_raw(fd)) + .map(|fd| WasiFd::from_raw(fd as c_int)) .map_err(err2io) } } pub fn readdir(&self, buf: &mut [u8], cookie: wasi::Dircookie) -> io::Result<usize> { - unsafe { wasi::fd_readdir(self.fd, buf.as_mut_ptr(), buf.len(), cookie).map_err(err2io) } + unsafe { + wasi::fd_readdir(self.fd as wasi::Fd, buf.as_mut_ptr(), buf.len(), cookie) + .map_err(err2io) + } } pub fn readlink(&self, path: &str, buf: &mut [u8]) -> io::Result<usize> { - unsafe { wasi::path_readlink(self.fd, path, buf.as_mut_ptr(), buf.len()).map_err(err2io) } + unsafe { + wasi::path_readlink(self.fd as wasi::Fd, path, buf.as_mut_ptr(), buf.len()) + .map_err(err2io) + } } pub fn rename(&self, old_path: &str, new_fd: &WasiFd, new_path: &str) -> io::Result<()> { - unsafe { wasi::path_rename(self.fd, old_path, new_fd.fd, new_path).map_err(err2io) } + unsafe { + wasi::path_rename(self.fd as wasi::Fd, old_path, new_fd.fd as wasi::Fd, new_path) + .map_err(err2io) + } } pub fn filestat_get(&self) -> io::Result<wasi::Filestat> { - unsafe { wasi::fd_filestat_get(self.fd).map_err(err2io) } + unsafe { wasi::fd_filestat_get(self.fd as wasi::Fd).map_err(err2io) } } pub fn filestat_set_times( @@ -157,11 +174,13 @@ impl WasiFd { mtim: wasi::Timestamp, fstflags: wasi::Fstflags, ) -> io::Result<()> { - unsafe { wasi::fd_filestat_set_times(self.fd, atim, mtim, fstflags).map_err(err2io) } + unsafe { + wasi::fd_filestat_set_times(self.fd as wasi::Fd, atim, mtim, fstflags).map_err(err2io) + } } pub fn filestat_set_size(&self, size: u64) -> io::Result<()> { - unsafe { wasi::fd_filestat_set_size(self.fd, size).map_err(err2io) } + unsafe { wasi::fd_filestat_set_size(self.fd as wasi::Fd, size).map_err(err2io) } } pub fn path_filestat_get( @@ -169,7 +188,7 @@ impl WasiFd { flags: wasi::Lookupflags, path: &str, ) -> io::Result<wasi::Filestat> { - unsafe { wasi::path_filestat_get(self.fd, flags, path).map_err(err2io) } + unsafe { wasi::path_filestat_get(self.fd as wasi::Fd, flags, path).map_err(err2io) } } pub fn path_filestat_set_times( @@ -181,21 +200,21 @@ impl WasiFd { fstflags: wasi::Fstflags, ) -> io::Result<()> { unsafe { - wasi::path_filestat_set_times(self.fd, flags, path, atim, mtim, fstflags) + wasi::path_filestat_set_times(self.fd as wasi::Fd, flags, path, atim, mtim, fstflags) .map_err(err2io) } } pub fn symlink(&self, old_path: &str, new_path: &str) -> io::Result<()> { - unsafe { wasi::path_symlink(old_path, self.fd, new_path).map_err(err2io) } + unsafe { wasi::path_symlink(old_path, self.fd as wasi::Fd, new_path).map_err(err2io) } } pub fn unlink_file(&self, path: &str) -> io::Result<()> { - unsafe { wasi::path_unlink_file(self.fd, path).map_err(err2io) } + unsafe { wasi::path_unlink_file(self.fd as wasi::Fd, path).map_err(err2io) } } pub fn remove_directory(&self, path: &str) -> io::Result<()> { - unsafe { wasi::path_remove_directory(self.fd, path).map_err(err2io) } + unsafe { wasi::path_remove_directory(self.fd as wasi::Fd, path).map_err(err2io) } } pub fn sock_recv( @@ -203,11 +222,11 @@ impl WasiFd { ri_data: &mut [IoSliceMut<'_>], ri_flags: wasi::Riflags, ) -> io::Result<(usize, wasi::Roflags)> { - unsafe { wasi::sock_recv(self.fd, iovec(ri_data), ri_flags).map_err(err2io) } + unsafe { wasi::sock_recv(self.fd as wasi::Fd, iovec(ri_data), ri_flags).map_err(err2io) } } pub fn sock_send(&self, si_data: &[IoSlice<'_>], si_flags: wasi::Siflags) -> io::Result<usize> { - unsafe { wasi::sock_send(self.fd, ciovec(si_data), si_flags).map_err(err2io) } + unsafe { wasi::sock_send(self.fd as wasi::Fd, ciovec(si_data), si_flags).map_err(err2io) } } pub fn sock_shutdown(&self, how: Shutdown) -> io::Result<()> { @@ -216,7 +235,7 @@ impl WasiFd { Shutdown::Write => wasi::SDFLAGS_WR, Shutdown::Both => wasi::SDFLAGS_WR | wasi::SDFLAGS_RD, }; - unsafe { wasi::sock_shutdown(self.fd, how).map_err(err2io) } + unsafe { wasi::sock_shutdown(self.fd as wasi::Fd, how).map_err(err2io) } } } @@ -224,6 +243,6 @@ impl Drop for WasiFd { fn drop(&mut self) { // FIXME: can we handle the return code here even though we can't on // unix? - let _ = unsafe { wasi::fd_close(self.fd) }; + let _ = unsafe { wasi::fd_close(self.fd as wasi::Fd) }; } } diff --git a/library/std/src/sys/wasi/fs.rs b/library/std/src/sys/wasi/fs.rs index 45e38f68b8c..55c9c652a8b 100644 --- a/library/std/src/sys/wasi/fs.rs +++ b/library/std/src/sys/wasi/fs.rs @@ -6,6 +6,7 @@ use crate::fmt; use crate::io::{self, IoSlice, IoSliceMut, SeekFrom}; use crate::iter; use crate::mem::{self, ManuallyDrop}; +use crate::os::raw::c_int; use crate::os::wasi::ffi::{OsStrExt, OsStringExt}; use crate::path::{Path, PathBuf}; use crate::ptr; @@ -454,8 +455,8 @@ impl File { } } -impl FromInner<u32> for File { - fn from_inner(fd: u32) -> File { +impl FromInner<c_int> for File { + fn from_inner(fd: c_int) -> File { unsafe { File { fd: WasiFd::from_raw(fd) } } } } @@ -648,12 +649,12 @@ fn open_parent(p: &Path) -> io::Result<(ManuallyDrop<WasiFd>, PathBuf)> { through which {:?} could be opened", p ); - return Err(io::Error::new(io::ErrorKind::Other, msg)); + return Err(io::Error::new(io::ErrorKind::Uncategorized, msg)); } let relative = CStr::from_ptr(relative_path).to_bytes().to_vec(); return Ok(( - ManuallyDrop::new(WasiFd::from_raw(fd as u32)), + ManuallyDrop::new(WasiFd::from_raw(fd as c_int)), PathBuf::from(OsString::from_vec(relative)), )); } @@ -670,7 +671,8 @@ fn open_parent(p: &Path) -> io::Result<(ManuallyDrop<WasiFd>, PathBuf)> { } pub fn osstr2str(f: &OsStr) -> io::Result<&str> { - f.to_str().ok_or_else(|| io::Error::new_const(io::ErrorKind::Other, &"input must be utf-8")) + f.to_str() + .ok_or_else(|| io::Error::new_const(io::ErrorKind::Uncategorized, &"input must be utf-8")) } pub fn copy(from: &Path, to: &Path) -> io::Result<u64> { diff --git a/library/std/src/sys/wasi/mod.rs b/library/std/src/sys/wasi/mod.rs index 45a829c0cd2..8d62335aae5 100644 --- a/library/std/src/sys/wasi/mod.rs +++ b/library/std/src/sys/wasi/mod.rs @@ -32,7 +32,8 @@ pub mod io; pub mod mutex; pub mod net; pub mod os; -pub use crate::sys_common::os_str_bytes as os_str; +#[path = "../unix/os_str.rs"] +pub mod os_str; #[path = "../unix/path.rs"] pub mod path; #[path = "../unsupported/pipe.rs"] @@ -58,7 +59,7 @@ pub use common::*; pub fn decode_error_kind(errno: i32) -> std_io::ErrorKind { use std_io::ErrorKind::*; if errno > u16::MAX as i32 || errno < 0 { - return Other; + return Uncategorized; } match errno as u16 { wasi::ERRNO_CONNREFUSED => ConnectionRefused, @@ -77,7 +78,7 @@ pub fn decode_error_kind(errno: i32) -> std_io::ErrorKind { wasi::ERRNO_AGAIN => WouldBlock, wasi::ERRNO_NOSYS => Unsupported, wasi::ERRNO_NOMEM => OutOfMemory, - _ => Other, + _ => Uncategorized, } } diff --git a/library/std/src/sys/wasi/net.rs b/library/std/src/sys/wasi/net.rs index 06860673d90..50b7352933e 100644 --- a/library/std/src/sys/wasi/net.rs +++ b/library/std/src/sys/wasi/net.rs @@ -5,6 +5,7 @@ use crate::convert::TryFrom; use crate::fmt; use crate::io::{self, IoSlice, IoSliceMut}; use crate::net::{Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr}; +use crate::os::raw::c_int; use crate::sys::unsupported; use crate::sys_common::FromInner; use crate::time::Duration; @@ -115,8 +116,8 @@ impl TcpStream { } } -impl FromInner<u32> for TcpStream { - fn from_inner(fd: u32) -> TcpStream { +impl FromInner<c_int> for TcpStream { + fn from_inner(fd: c_int) -> TcpStream { unsafe { TcpStream { fd: WasiFd::from_raw(fd) } } } } @@ -181,8 +182,8 @@ impl TcpListener { } } -impl FromInner<u32> for TcpListener { - fn from_inner(fd: u32) -> TcpListener { +impl FromInner<c_int> for TcpListener { + fn from_inner(fd: c_int) -> TcpListener { unsafe { TcpListener { fd: WasiFd::from_raw(fd) } } } } @@ -331,8 +332,8 @@ impl UdpSocket { } } -impl FromInner<u32> for UdpSocket { - fn from_inner(fd: u32) -> UdpSocket { +impl FromInner<c_int> for UdpSocket { + fn from_inner(fd: c_int) -> UdpSocket { unsafe { UdpSocket { fd: WasiFd::from_raw(fd) } } } } diff --git a/library/std/src/sys/wasi/os.rs b/library/std/src/sys/wasi/os.rs index f129ee55a83..c5229a18834 100644 --- a/library/std/src/sys/wasi/os.rs +++ b/library/std/src/sys/wasi/os.rs @@ -175,17 +175,16 @@ pub fn env() -> Env { } } -pub fn getenv(k: &OsStr) -> io::Result<Option<OsString>> { - let k = CString::new(k.as_bytes())?; +pub fn getenv(k: &OsStr) -> Option<OsString> { + let k = CString::new(k.as_bytes()).ok()?; unsafe { let _guard = env_lock(); let s = libc::getenv(k.as_ptr()) as *const libc::c_char; - let ret = if s.is_null() { + if s.is_null() { None } else { Some(OsStringExt::from_vec(CStr::from_ptr(s).to_bytes().to_vec())) - }; - Ok(ret) + } } } diff --git a/library/std/src/sys/wasi/stdio.rs b/library/std/src/sys/wasi/stdio.rs index 209d5b996e5..8782f333a1f 100644 --- a/library/std/src/sys/wasi/stdio.rs +++ b/library/std/src/sys/wasi/stdio.rs @@ -3,6 +3,7 @@ use super::fd::WasiFd; use crate::io::{self, IoSlice, IoSliceMut}; use crate::mem::ManuallyDrop; +use crate::os::raw; pub struct Stdin; pub struct Stdout; @@ -14,7 +15,7 @@ impl Stdin { } #[inline] - pub fn as_raw_fd(&self) -> u32 { + pub fn as_raw_fd(&self) -> raw::c_int { 0 } } @@ -40,7 +41,7 @@ impl Stdout { } #[inline] - pub fn as_raw_fd(&self) -> u32 { + pub fn as_raw_fd(&self) -> raw::c_int { 1 } } @@ -69,7 +70,7 @@ impl Stderr { } #[inline] - pub fn as_raw_fd(&self) -> u32 { + pub fn as_raw_fd(&self) -> raw::c_int { 2 } } diff --git a/library/std/src/sys/wasi/thread.rs b/library/std/src/sys/wasi/thread.rs index 74515553a82..9ec02bbec26 100644 --- a/library/std/src/sys/wasi/thread.rs +++ b/library/std/src/sys/wasi/thread.rs @@ -3,6 +3,7 @@ use crate::ffi::CStr; use crate::io; use crate::mem; +use crate::num::NonZeroUsize; use crate::sys::unsupported; use crate::time::Duration; @@ -63,6 +64,10 @@ impl Thread { } } +pub fn available_concurrency() -> io::Result<NonZeroUsize> { + unsupported() +} + pub mod guard { pub type Guard = !; pub unsafe fn current() -> Option<Guard> { diff --git a/library/std/src/sys/wasm/atomics/rwlock.rs b/library/std/src/sys/wasm/atomics/rwlock.rs index 06442e925f4..64eaa2fc482 100644 --- a/library/std/src/sys/wasm/atomics/rwlock.rs +++ b/library/std/src/sys/wasm/atomics/rwlock.rs @@ -8,6 +8,8 @@ pub struct RWLock { state: UnsafeCell<State>, } +pub type MovableRWLock = RWLock; + enum State { Unlocked, Reading(usize), diff --git a/library/std/src/sys/wasm/atomics/thread.rs b/library/std/src/sys/wasm/atomics/thread.rs index 54bc877aa7d..a66ab083757 100644 --- a/library/std/src/sys/wasm/atomics/thread.rs +++ b/library/std/src/sys/wasm/atomics/thread.rs @@ -1,5 +1,6 @@ use crate::ffi::CStr; use crate::io; +use crate::num::NonZeroUsize; use crate::sys::unsupported; use crate::time::Duration; @@ -39,6 +40,10 @@ impl Thread { pub fn join(self) {} } +pub fn available_concurrency() -> io::Result<NonZeroUsize> { + unsupported() +} + pub mod guard { pub type Guard = !; pub unsafe fn current() -> Option<Guard> { diff --git a/library/std/src/sys/wasm/mod.rs b/library/std/src/sys/wasm/mod.rs index cd701a333f8..c81d653a5e3 100644 --- a/library/std/src/sys/wasm/mod.rs +++ b/library/std/src/sys/wasm/mod.rs @@ -30,6 +30,8 @@ pub mod io; pub mod net; #[path = "../unsupported/os.rs"] pub mod os; +#[path = "../unix/os_str.rs"] +pub mod os_str; #[path = "../unix/path.rs"] pub mod path; #[path = "../unsupported/pipe.rs"] @@ -45,8 +47,6 @@ pub mod thread_local_key; #[path = "../unsupported/time.rs"] pub mod time; -pub use crate::sys_common::os_str_bytes as os_str; - cfg_if::cfg_if! { if #[cfg(target_feature = "atomics")] { #[path = "atomics/condvar.rs"] diff --git a/library/std/src/sys/windows/c.rs b/library/std/src/sys/windows/c.rs index b7efc884473..63f9be7b7e3 100644 --- a/library/std/src/sys/windows/c.rs +++ b/library/std/src/sys/windows/c.rs @@ -10,9 +10,14 @@ use crate::ptr; use libc::{c_void, size_t, wchar_t}; +#[path = "c/errors.rs"] // c.rs is included from two places so we need to specify this +mod errors; +pub use errors::*; + pub use self::EXCEPTION_DISPOSITION::*; pub use self::FILE_INFO_BY_HANDLE_CLASS::*; +pub type DWORD_PTR = ULONG_PTR; pub type DWORD = c_ulong; pub type NonZeroDWORD = NonZero_c_ulong; pub type HANDLE = LPVOID; @@ -53,6 +58,7 @@ pub type LPWSADATA = *mut WSADATA; pub type LPWSAPROTOCOL_INFO = *mut WSAPROTOCOL_INFO; pub type LPWSTR = *mut WCHAR; pub type LPFILETIME = *mut FILETIME; +pub type LPSYSTEM_INFO = *mut SYSTEM_INFO; pub type LPWSABUF = *mut WSABUF; pub type LPWSAOVERLAPPED = *mut c_void; pub type LPWSAOVERLAPPED_COMPLETION_ROUTINE = *mut c_void; @@ -68,6 +74,10 @@ pub type ADDRESS_FAMILY = USHORT; pub const TRUE: BOOL = 1; pub const FALSE: BOOL = 0; +pub const CSTR_LESS_THAN: c_int = 1; +pub const CSTR_EQUAL: c_int = 2; +pub const CSTR_GREATER_THAN: c_int = 3; + pub const FILE_ATTRIBUTE_READONLY: DWORD = 0x1; pub const FILE_ATTRIBUTE_DIRECTORY: DWORD = 0x10; pub const FILE_ATTRIBUTE_REPARSE_POINT: DWORD = 0x400; @@ -132,19 +142,6 @@ pub const WSASYS_STATUS_LEN: usize = 128; pub const WSAPROTOCOL_LEN: DWORD = 255; pub const INVALID_SOCKET: SOCKET = !0; -pub const WSAEACCES: c_int = 10013; -pub const WSAEINVAL: c_int = 10022; -pub const WSAEWOULDBLOCK: c_int = 10035; -pub const WSAEPROTOTYPE: c_int = 10041; -pub const WSAEADDRINUSE: c_int = 10048; -pub const WSAEADDRNOTAVAIL: c_int = 10049; -pub const WSAECONNABORTED: c_int = 10053; -pub const WSAECONNRESET: c_int = 10054; -pub const WSAENOTCONN: c_int = 10057; -pub const WSAESHUTDOWN: c_int = 10058; -pub const WSAETIMEDOUT: c_int = 10060; -pub const WSAECONNREFUSED: c_int = 10061; - pub const MAX_PROTOCOL_CHAIN: DWORD = 7; pub const MAXIMUM_REPARSE_DATA_BUFFER_SIZE: usize = 16 * 1024; @@ -164,42 +161,6 @@ pub const STD_ERROR_HANDLE: DWORD = -12i32 as DWORD; pub const PROGRESS_CONTINUE: DWORD = 0; -// List of Windows system error codes with descriptions: -// https://docs.microsoft.com/en-us/windows/win32/debug/system-error-codes#system-error-codes -pub const ERROR_FILE_NOT_FOUND: DWORD = 2; -pub const ERROR_PATH_NOT_FOUND: DWORD = 3; -pub const ERROR_ACCESS_DENIED: DWORD = 5; -pub const ERROR_INVALID_HANDLE: DWORD = 6; -pub const ERROR_NOT_ENOUGH_MEMORY: DWORD = 8; -pub const ERROR_OUTOFMEMORY: DWORD = 14; -pub const ERROR_NO_MORE_FILES: DWORD = 18; -pub const ERROR_SHARING_VIOLATION: u32 = 32; -pub const ERROR_HANDLE_EOF: DWORD = 38; -pub const ERROR_FILE_EXISTS: DWORD = 80; -pub const ERROR_INVALID_PARAMETER: DWORD = 87; -pub const ERROR_BROKEN_PIPE: DWORD = 109; -pub const ERROR_CALL_NOT_IMPLEMENTED: DWORD = 120; -pub const ERROR_SEM_TIMEOUT: DWORD = 121; -pub const ERROR_INSUFFICIENT_BUFFER: DWORD = 122; -pub const ERROR_ALREADY_EXISTS: DWORD = 183; -pub const ERROR_ENVVAR_NOT_FOUND: DWORD = 203; -pub const ERROR_NO_DATA: DWORD = 232; -pub const ERROR_DRIVER_CANCEL_TIMEOUT: DWORD = 594; -pub const ERROR_OPERATION_ABORTED: DWORD = 995; -pub const ERROR_IO_PENDING: DWORD = 997; -pub const ERROR_SERVICE_REQUEST_TIMEOUT: DWORD = 1053; -pub const ERROR_COUNTER_TIMEOUT: DWORD = 1121; -pub const ERROR_TIMEOUT: DWORD = 1460; -pub const ERROR_RESOURCE_CALL_TIMED_OUT: DWORD = 5910; -pub const ERROR_CTX_MODEM_RESPONSE_TIMEOUT: DWORD = 7012; -pub const ERROR_CTX_CLIENT_QUERY_TIMEOUT: DWORD = 7040; -pub const FRS_ERR_SYSVOL_POPULATE_TIMEOUT: DWORD = 8014; -pub const ERROR_DS_TIMELIMIT_EXCEEDED: DWORD = 8226; -pub const DNS_ERROR_RECORD_TIMED_OUT: DWORD = 9705; -pub const ERROR_IPSEC_IKE_TIMED_OUT: DWORD = 13805; -pub const ERROR_RUNLEVEL_SWITCH_TIMEOUT: DWORD = 15402; -pub const ERROR_RUNLEVEL_SWITCH_AGENT_TIMEOUT: DWORD = 15403; - pub const E_NOTIMPL: HRESULT = 0x80004001u32 as HRESULT; pub const INVALID_HANDLE_VALUE: HANDLE = !0 as HANDLE; @@ -234,6 +195,7 @@ pub const SD_RECEIVE: c_int = 0; pub const SD_SEND: c_int = 1; pub const SOCK_DGRAM: c_int = 2; pub const SOCK_STREAM: c_int = 1; +pub const SOCKET_ERROR: c_int = -1; pub const SOL_SOCKET: c_int = 0xffff; pub const SO_RCVTIMEO: c_int = 0x1006; pub const SO_SNDTIMEO: c_int = 0x1005; @@ -533,6 +495,21 @@ pub struct FILETIME { } #[repr(C)] +pub struct SYSTEM_INFO { + pub wProcessorArchitecture: WORD, + pub wReserved: WORD, + pub dwPageSize: DWORD, + pub lpMinimumApplicationAddress: LPVOID, + pub lpMaximumApplicationAddress: LPVOID, + pub dwActiveProcessorMask: DWORD_PTR, + pub dwNumberOfProcessors: DWORD, + pub dwProcessorType: DWORD, + pub dwAllocationGranularity: DWORD, + pub wProcessorLevel: WORD, + pub wProcessorRevision: WORD, +} + +#[repr(C)] pub struct OVERLAPPED { pub Internal: *mut c_ulong, pub InternalHigh: *mut c_ulong, @@ -933,6 +910,7 @@ extern "system" { pub fn GetModuleHandleW(lpModuleName: LPCWSTR) -> HMODULE; pub fn GetSystemTimeAsFileTime(lpSystemTimeAsFileTime: LPFILETIME); + pub fn GetSystemInfo(lpSystemInfo: LPSYSTEM_INFO); pub fn CreateEventW( lpEventAttributes: LPSECURITY_ATTRIBUTES, @@ -996,6 +974,14 @@ extern "system" { pub fn ReleaseSRWLockShared(SRWLock: PSRWLOCK); pub fn TryAcquireSRWLockExclusive(SRWLock: PSRWLOCK) -> BOOLEAN; pub fn TryAcquireSRWLockShared(SRWLock: PSRWLOCK) -> BOOLEAN; + + pub fn CompareStringOrdinal( + lpString1: LPCWSTR, + cchCount1: c_int, + lpString2: LPCWSTR, + cchCount2: c_int, + bIgnoreCase: BOOL, + ) -> c_int; } #[link(name = "ws2_32")] diff --git a/library/std/src/sys/windows/c/errors.rs b/library/std/src/sys/windows/c/errors.rs new file mode 100644 index 00000000000..23dcc119db9 --- /dev/null +++ b/library/std/src/sys/windows/c/errors.rs @@ -0,0 +1,1883 @@ +// List of Windows system error codes with descriptions: +// https://docs.microsoft.com/en-us/windows/win32/debug/system-error-codes#system-error-codes + +#![allow(dead_code)] + +use super::{c_int, DWORD}; + +pub const ERROR_DIRECTORY_NOT_SUPPORTED: DWORD = 336; +pub const ERROR_DRIVER_CANCEL_TIMEOUT: DWORD = 594; +pub const ERROR_DISK_QUOTA_EXCEEDED: DWORD = 1295; +pub const ERROR_RESOURCE_CALL_TIMED_OUT: DWORD = 5910; +pub const FRS_ERR_SYSVOL_POPULATE_TIMEOUT: DWORD = 8014; +pub const DNS_ERROR_RECORD_TIMED_OUT: DWORD = 9705; + +// The followiung list was obtained from +// `/usr/x86_64-w64-mingw32/include/winerror.h` +// in the Debian package +// mingw-w64_6.0.0-3_all.deb +// +// The header of that file says: +// * This file has no copyright assigned and is placed in the Public Domain. +// * This file is part of the mingw-w64 runtime package. +// * No warranty is given; refer to the file DISCLAIMER.PD within this package. +// +// The text here is the result of the following rune: +// grep -P '#define ERROR' /usr/x86_64-w64-mingw32/include/winerror.h >>library/std/src/sys/windows/c/errors.rs +// grep -P '#define WSA' /usr/x86_64-w64-mingw32/include/winerror.h >>library/std/src/sys/windows/c/errors.rs +// and then using some manually-invented but rather obvious editor search-and-replace +// invocations, plus some straightforward manual fixups, to turn it into Rust syntax +// and remove all the duplicates from the manual table above. + +pub const ERROR_SUCCESS: DWORD = 0; +pub const ERROR_INVALID_FUNCTION: DWORD = 1; +pub const ERROR_FILE_NOT_FOUND: DWORD = 2; +pub const ERROR_PATH_NOT_FOUND: DWORD = 3; +pub const ERROR_TOO_MANY_OPEN_FILES: DWORD = 4; +pub const ERROR_ACCESS_DENIED: DWORD = 5; +pub const ERROR_INVALID_HANDLE: DWORD = 6; +pub const ERROR_ARENA_TRASHED: DWORD = 7; +pub const ERROR_NOT_ENOUGH_MEMORY: DWORD = 8; +pub const ERROR_INVALID_BLOCK: DWORD = 9; +pub const ERROR_BAD_ENVIRONMENT: DWORD = 10; +pub const ERROR_BAD_FORMAT: DWORD = 11; +pub const ERROR_INVALID_ACCESS: DWORD = 12; +pub const ERROR_INVALID_DATA: DWORD = 13; +pub const ERROR_OUTOFMEMORY: DWORD = 14; +pub const ERROR_INVALID_DRIVE: DWORD = 15; +pub const ERROR_CURRENT_DIRECTORY: DWORD = 16; +pub const ERROR_NOT_SAME_DEVICE: DWORD = 17; +pub const ERROR_NO_MORE_FILES: DWORD = 18; +pub const ERROR_WRITE_PROTECT: DWORD = 19; +pub const ERROR_BAD_UNIT: DWORD = 20; +pub const ERROR_NOT_READY: DWORD = 21; +pub const ERROR_BAD_COMMAND: DWORD = 22; +pub const ERROR_CRC: DWORD = 23; +pub const ERROR_BAD_LENGTH: DWORD = 24; +pub const ERROR_SEEK: DWORD = 25; +pub const ERROR_NOT_DOS_DISK: DWORD = 26; +pub const ERROR_SECTOR_NOT_FOUND: DWORD = 27; +pub const ERROR_OUT_OF_PAPER: DWORD = 28; +pub const ERROR_WRITE_FAULT: DWORD = 29; +pub const ERROR_READ_FAULT: DWORD = 30; +pub const ERROR_GEN_FAILURE: DWORD = 31; +pub const ERROR_SHARING_VIOLATION: DWORD = 32; +pub const ERROR_LOCK_VIOLATION: DWORD = 33; +pub const ERROR_WRONG_DISK: DWORD = 34; +pub const ERROR_SHARING_BUFFER_EXCEEDED: DWORD = 36; +pub const ERROR_HANDLE_EOF: DWORD = 38; +pub const ERROR_HANDLE_DISK_FULL: DWORD = 39; +pub const ERROR_NOT_SUPPORTED: DWORD = 50; +pub const ERROR_REM_NOT_LIST: DWORD = 51; +pub const ERROR_DUP_NAME: DWORD = 52; +pub const ERROR_BAD_NETPATH: DWORD = 53; +pub const ERROR_NETWORK_BUSY: DWORD = 54; +pub const ERROR_DEV_NOT_EXIST: DWORD = 55; +pub const ERROR_TOO_MANY_CMDS: DWORD = 56; +pub const ERROR_ADAP_HDW_ERR: DWORD = 57; +pub const ERROR_BAD_NET_RESP: DWORD = 58; +pub const ERROR_UNEXP_NET_ERR: DWORD = 59; +pub const ERROR_BAD_REM_ADAP: DWORD = 60; +pub const ERROR_PRINTQ_FULL: DWORD = 61; +pub const ERROR_NO_SPOOL_SPACE: DWORD = 62; +pub const ERROR_PRINT_CANCELLED: DWORD = 63; +pub const ERROR_NETNAME_DELETED: DWORD = 64; +pub const ERROR_NETWORK_ACCESS_DENIED: DWORD = 65; +pub const ERROR_BAD_DEV_TYPE: DWORD = 66; +pub const ERROR_BAD_NET_NAME: DWORD = 67; +pub const ERROR_TOO_MANY_NAMES: DWORD = 68; +pub const ERROR_TOO_MANY_SESS: DWORD = 69; +pub const ERROR_SHARING_PAUSED: DWORD = 70; +pub const ERROR_REQ_NOT_ACCEP: DWORD = 71; +pub const ERROR_REDIR_PAUSED: DWORD = 72; +pub const ERROR_FILE_EXISTS: DWORD = 80; +pub const ERROR_CANNOT_MAKE: DWORD = 82; +pub const ERROR_FAIL_I24: DWORD = 83; +pub const ERROR_OUT_OF_STRUCTURES: DWORD = 84; +pub const ERROR_ALREADY_ASSIGNED: DWORD = 85; +pub const ERROR_INVALID_PASSWORD: DWORD = 86; +pub const ERROR_INVALID_PARAMETER: DWORD = 87; +pub const ERROR_NET_WRITE_FAULT: DWORD = 88; +pub const ERROR_NO_PROC_SLOTS: DWORD = 89; +pub const ERROR_TOO_MANY_SEMAPHORES: DWORD = 100; +pub const ERROR_EXCL_SEM_ALREADY_OWNED: DWORD = 101; +pub const ERROR_SEM_IS_SET: DWORD = 102; +pub const ERROR_TOO_MANY_SEM_REQUESTS: DWORD = 103; +pub const ERROR_INVALID_AT_INTERRUPT_TIME: DWORD = 104; +pub const ERROR_SEM_OWNER_DIED: DWORD = 105; +pub const ERROR_SEM_USER_LIMIT: DWORD = 106; +pub const ERROR_DISK_CHANGE: DWORD = 107; +pub const ERROR_DRIVE_LOCKED: DWORD = 108; +pub const ERROR_BROKEN_PIPE: DWORD = 109; +pub const ERROR_OPEN_FAILED: DWORD = 110; +pub const ERROR_BUFFER_OVERFLOW: DWORD = 111; +pub const ERROR_DISK_FULL: DWORD = 112; +pub const ERROR_NO_MORE_SEARCH_HANDLES: DWORD = 113; +pub const ERROR_INVALID_TARGET_HANDLE: DWORD = 114; +pub const ERROR_INVALID_CATEGORY: DWORD = 117; +pub const ERROR_INVALID_VERIFY_SWITCH: DWORD = 118; +pub const ERROR_BAD_DRIVER_LEVEL: DWORD = 119; +pub const ERROR_CALL_NOT_IMPLEMENTED: DWORD = 120; +pub const ERROR_SEM_TIMEOUT: DWORD = 121; +pub const ERROR_INSUFFICIENT_BUFFER: DWORD = 122; +pub const ERROR_INVALID_NAME: DWORD = 123; +pub const ERROR_INVALID_LEVEL: DWORD = 124; +pub const ERROR_NO_VOLUME_LABEL: DWORD = 125; +pub const ERROR_MOD_NOT_FOUND: DWORD = 126; +pub const ERROR_PROC_NOT_FOUND: DWORD = 127; +pub const ERROR_WAIT_NO_CHILDREN: DWORD = 128; +pub const ERROR_CHILD_NOT_COMPLETE: DWORD = 129; +pub const ERROR_DIRECT_ACCESS_HANDLE: DWORD = 130; +pub const ERROR_NEGATIVE_SEEK: DWORD = 131; +pub const ERROR_SEEK_ON_DEVICE: DWORD = 132; +pub const ERROR_IS_JOIN_TARGET: DWORD = 133; +pub const ERROR_IS_JOINED: DWORD = 134; +pub const ERROR_IS_SUBSTED: DWORD = 135; +pub const ERROR_NOT_JOINED: DWORD = 136; +pub const ERROR_NOT_SUBSTED: DWORD = 137; +pub const ERROR_JOIN_TO_JOIN: DWORD = 138; +pub const ERROR_SUBST_TO_SUBST: DWORD = 139; +pub const ERROR_JOIN_TO_SUBST: DWORD = 140; +pub const ERROR_SUBST_TO_JOIN: DWORD = 141; +pub const ERROR_BUSY_DRIVE: DWORD = 142; +pub const ERROR_SAME_DRIVE: DWORD = 143; +pub const ERROR_DIR_NOT_ROOT: DWORD = 144; +pub const ERROR_DIR_NOT_EMPTY: DWORD = 145; +pub const ERROR_IS_SUBST_PATH: DWORD = 146; +pub const ERROR_IS_JOIN_PATH: DWORD = 147; +pub const ERROR_PATH_BUSY: DWORD = 148; +pub const ERROR_IS_SUBST_TARGET: DWORD = 149; +pub const ERROR_SYSTEM_TRACE: DWORD = 150; +pub const ERROR_INVALID_EVENT_COUNT: DWORD = 151; +pub const ERROR_TOO_MANY_MUXWAITERS: DWORD = 152; +pub const ERROR_INVALID_LIST_FORMAT: DWORD = 153; +pub const ERROR_LABEL_TOO_LONG: DWORD = 154; +pub const ERROR_TOO_MANY_TCBS: DWORD = 155; +pub const ERROR_SIGNAL_REFUSED: DWORD = 156; +pub const ERROR_DISCARDED: DWORD = 157; +pub const ERROR_NOT_LOCKED: DWORD = 158; +pub const ERROR_BAD_THREADID_ADDR: DWORD = 159; +pub const ERROR_BAD_ARGUMENTS: DWORD = 160; +pub const ERROR_BAD_PATHNAME: DWORD = 161; +pub const ERROR_SIGNAL_PENDING: DWORD = 162; +pub const ERROR_MAX_THRDS_REACHED: DWORD = 164; +pub const ERROR_LOCK_FAILED: DWORD = 167; +pub const ERROR_BUSY: DWORD = 170; +pub const ERROR_CANCEL_VIOLATION: DWORD = 173; +pub const ERROR_ATOMIC_LOCKS_NOT_SUPPORTED: DWORD = 174; +pub const ERROR_INVALID_SEGMENT_NUMBER: DWORD = 180; +pub const ERROR_INVALID_ORDINAL: DWORD = 182; +pub const ERROR_ALREADY_EXISTS: DWORD = 183; +pub const ERROR_INVALID_FLAG_NUMBER: DWORD = 186; +pub const ERROR_SEM_NOT_FOUND: DWORD = 187; +pub const ERROR_INVALID_STARTING_CODESEG: DWORD = 188; +pub const ERROR_INVALID_STACKSEG: DWORD = 189; +pub const ERROR_INVALID_MODULETYPE: DWORD = 190; +pub const ERROR_INVALID_EXE_SIGNATURE: DWORD = 191; +pub const ERROR_EXE_MARKED_INVALID: DWORD = 192; +pub const ERROR_BAD_EXE_FORMAT: DWORD = 193; +pub const ERROR_ITERATED_DATA_EXCEEDS_64k: DWORD = 194; +pub const ERROR_INVALID_MINALLOCSIZE: DWORD = 195; +pub const ERROR_DYNLINK_FROM_INVALID_RING: DWORD = 196; +pub const ERROR_IOPL_NOT_ENABLED: DWORD = 197; +pub const ERROR_INVALID_SEGDPL: DWORD = 198; +pub const ERROR_AUTODATASEG_EXCEEDS_64k: DWORD = 199; +pub const ERROR_RING2SEG_MUST_BE_MOVABLE: DWORD = 200; +pub const ERROR_RELOC_CHAIN_XEEDS_SEGLIM: DWORD = 201; +pub const ERROR_INFLOOP_IN_RELOC_CHAIN: DWORD = 202; +pub const ERROR_ENVVAR_NOT_FOUND: DWORD = 203; +pub const ERROR_NO_SIGNAL_SENT: DWORD = 205; +pub const ERROR_FILENAME_EXCED_RANGE: DWORD = 206; +pub const ERROR_RING2_STACK_IN_USE: DWORD = 207; +pub const ERROR_META_EXPANSION_TOO_LONG: DWORD = 208; +pub const ERROR_INVALID_SIGNAL_NUMBER: DWORD = 209; +pub const ERROR_THREAD_1_INACTIVE: DWORD = 210; +pub const ERROR_LOCKED: DWORD = 212; +pub const ERROR_TOO_MANY_MODULES: DWORD = 214; +pub const ERROR_NESTING_NOT_ALLOWED: DWORD = 215; +pub const ERROR_EXE_MACHINE_TYPE_MISMATCH: DWORD = 216; +pub const ERROR_EXE_CANNOT_MODIFY_SIGNED_BINARY: DWORD = 217; +pub const ERROR_EXE_CANNOT_MODIFY_STRONG_SIGNED_BINARY: DWORD = 218; +pub const ERROR_FILE_CHECKED_OUT: DWORD = 220; +pub const ERROR_CHECKOUT_REQUIRED: DWORD = 221; +pub const ERROR_BAD_FILE_TYPE: DWORD = 222; +pub const ERROR_FILE_TOO_LARGE: DWORD = 223; +pub const ERROR_FORMS_AUTH_REQUIRED: DWORD = 224; +pub const ERROR_PIPE_LOCAL: DWORD = 229; +pub const ERROR_BAD_PIPE: DWORD = 230; +pub const ERROR_PIPE_BUSY: DWORD = 231; +pub const ERROR_NO_DATA: DWORD = 232; +pub const ERROR_PIPE_NOT_CONNECTED: DWORD = 233; +pub const ERROR_MORE_DATA: DWORD = 234; +pub const ERROR_VC_DISCONNECTED: DWORD = 240; +pub const ERROR_INVALID_EA_NAME: DWORD = 254; +pub const ERROR_EA_LIST_INCONSISTENT: DWORD = 255; +pub const ERROR_NO_MORE_ITEMS: DWORD = 259; +pub const ERROR_CANNOT_COPY: DWORD = 266; +pub const ERROR_DIRECTORY: DWORD = 267; +pub const ERROR_EAS_DIDNT_FIT: DWORD = 275; +pub const ERROR_EA_FILE_CORRUPT: DWORD = 276; +pub const ERROR_EA_TABLE_FULL: DWORD = 277; +pub const ERROR_INVALID_EA_HANDLE: DWORD = 278; +pub const ERROR_EAS_NOT_SUPPORTED: DWORD = 282; +pub const ERROR_NOT_OWNER: DWORD = 288; +pub const ERROR_TOO_MANY_POSTS: DWORD = 298; +pub const ERROR_PARTIAL_COPY: DWORD = 299; +pub const ERROR_OPLOCK_NOT_GRANTED: DWORD = 300; +pub const ERROR_INVALID_OPLOCK_PROTOCOL: DWORD = 301; +pub const ERROR_DISK_TOO_FRAGMENTED: DWORD = 302; +pub const ERROR_DELETE_PENDING: DWORD = 303; +pub const ERROR_INVALID_TOKEN: DWORD = 315; +pub const ERROR_MR_MID_NOT_FOUND: DWORD = 317; +pub const ERROR_SCOPE_NOT_FOUND: DWORD = 318; +pub const ERROR_INVALID_ADDRESS: DWORD = 487; +pub const ERROR_ARITHMETIC_OVERFLOW: DWORD = 534; +pub const ERROR_PIPE_CONNECTED: DWORD = 535; +pub const ERROR_PIPE_LISTENING: DWORD = 536; +pub const ERROR_WAKE_SYSTEM: DWORD = 730; +pub const ERROR_WAIT_1: DWORD = 731; +pub const ERROR_WAIT_2: DWORD = 732; +pub const ERROR_WAIT_3: DWORD = 733; +pub const ERROR_WAIT_63: DWORD = 734; +pub const ERROR_ABANDONED_WAIT_0: DWORD = 735; +pub const ERROR_ABANDONED_WAIT_63: DWORD = 736; +pub const ERROR_USER_APC: DWORD = 737; +pub const ERROR_KERNEL_APC: DWORD = 738; +pub const ERROR_ALERTED: DWORD = 739; +pub const ERROR_EA_ACCESS_DENIED: DWORD = 994; +pub const ERROR_OPERATION_ABORTED: DWORD = 995; +pub const ERROR_IO_INCOMPLETE: DWORD = 996; +pub const ERROR_IO_PENDING: DWORD = 997; +pub const ERROR_NOACCESS: DWORD = 998; +pub const ERROR_SWAPERROR: DWORD = 999; +pub const ERROR_STACK_OVERFLOW: DWORD = 1001; +pub const ERROR_INVALID_MESSAGE: DWORD = 1002; +pub const ERROR_CAN_NOT_COMPLETE: DWORD = 1003; +pub const ERROR_INVALID_FLAGS: DWORD = 1004; +pub const ERROR_UNRECOGNIZED_VOLUME: DWORD = 1005; +pub const ERROR_FILE_INVALID: DWORD = 1006; +pub const ERROR_FULLSCREEN_MODE: DWORD = 1007; +pub const ERROR_NO_TOKEN: DWORD = 1008; +pub const ERROR_BADDB: DWORD = 1009; +pub const ERROR_BADKEY: DWORD = 1010; +pub const ERROR_CANTOPEN: DWORD = 1011; +pub const ERROR_CANTREAD: DWORD = 1012; +pub const ERROR_CANTWRITE: DWORD = 1013; +pub const ERROR_REGISTRY_RECOVERED: DWORD = 1014; +pub const ERROR_REGISTRY_CORRUPT: DWORD = 1015; +pub const ERROR_REGISTRY_IO_FAILED: DWORD = 1016; +pub const ERROR_NOT_REGISTRY_FILE: DWORD = 1017; +pub const ERROR_KEY_DELETED: DWORD = 1018; +pub const ERROR_NO_LOG_SPACE: DWORD = 1019; +pub const ERROR_KEY_HAS_CHILDREN: DWORD = 1020; +pub const ERROR_CHILD_MUST_BE_VOLATILE: DWORD = 1021; +pub const ERROR_NOTIFY_ENUM_DIR: DWORD = 1022; +pub const ERROR_DEPENDENT_SERVICES_RUNNING: DWORD = 1051; +pub const ERROR_INVALID_SERVICE_CONTROL: DWORD = 1052; +pub const ERROR_SERVICE_REQUEST_TIMEOUT: DWORD = 1053; +pub const ERROR_SERVICE_NO_THREAD: DWORD = 1054; +pub const ERROR_SERVICE_DATABASE_LOCKED: DWORD = 1055; +pub const ERROR_SERVICE_ALREADY_RUNNING: DWORD = 1056; +pub const ERROR_INVALID_SERVICE_ACCOUNT: DWORD = 1057; +pub const ERROR_SERVICE_DISABLED: DWORD = 1058; +pub const ERROR_CIRCULAR_DEPENDENCY: DWORD = 1059; +pub const ERROR_SERVICE_DOES_NOT_EXIST: DWORD = 1060; +pub const ERROR_SERVICE_CANNOT_ACCEPT_CTRL: DWORD = 1061; +pub const ERROR_SERVICE_NOT_ACTIVE: DWORD = 1062; +pub const ERROR_FAILED_SERVICE_CONTROLLER_CONNECT: DWORD = 1063; +pub const ERROR_EXCEPTION_IN_SERVICE: DWORD = 1064; +pub const ERROR_DATABASE_DOES_NOT_EXIST: DWORD = 1065; +pub const ERROR_SERVICE_SPECIFIC_ERROR: DWORD = 1066; +pub const ERROR_PROCESS_ABORTED: DWORD = 1067; +pub const ERROR_SERVICE_DEPENDENCY_FAIL: DWORD = 1068; +pub const ERROR_SERVICE_LOGON_FAILED: DWORD = 1069; +pub const ERROR_SERVICE_START_HANG: DWORD = 1070; +pub const ERROR_INVALID_SERVICE_LOCK: DWORD = 1071; +pub const ERROR_SERVICE_MARKED_FOR_DELETE: DWORD = 1072; +pub const ERROR_SERVICE_EXISTS: DWORD = 1073; +pub const ERROR_ALREADY_RUNNING_LKG: DWORD = 1074; +pub const ERROR_SERVICE_DEPENDENCY_DELETED: DWORD = 1075; +pub const ERROR_BOOT_ALREADY_ACCEPTED: DWORD = 1076; +pub const ERROR_SERVICE_NEVER_STARTED: DWORD = 1077; +pub const ERROR_DUPLICATE_SERVICE_NAME: DWORD = 1078; +pub const ERROR_DIFFERENT_SERVICE_ACCOUNT: DWORD = 1079; +pub const ERROR_CANNOT_DETECT_DRIVER_FAILURE: DWORD = 1080; +pub const ERROR_CANNOT_DETECT_PROCESS_ABORT: DWORD = 1081; +pub const ERROR_NO_RECOVERY_PROGRAM: DWORD = 1082; +pub const ERROR_SERVICE_NOT_IN_EXE: DWORD = 1083; +pub const ERROR_NOT_SAFEBOOT_SERVICE: DWORD = 1084; +pub const ERROR_END_OF_MEDIA: DWORD = 1100; +pub const ERROR_FILEMARK_DETECTED: DWORD = 1101; +pub const ERROR_BEGINNING_OF_MEDIA: DWORD = 1102; +pub const ERROR_SETMARK_DETECTED: DWORD = 1103; +pub const ERROR_NO_DATA_DETECTED: DWORD = 1104; +pub const ERROR_PARTITION_FAILURE: DWORD = 1105; +pub const ERROR_INVALID_BLOCK_LENGTH: DWORD = 1106; +pub const ERROR_DEVICE_NOT_PARTITIONED: DWORD = 1107; +pub const ERROR_UNABLE_TO_LOCK_MEDIA: DWORD = 1108; +pub const ERROR_UNABLE_TO_UNLOAD_MEDIA: DWORD = 1109; +pub const ERROR_MEDIA_CHANGED: DWORD = 1110; +pub const ERROR_BUS_RESET: DWORD = 1111; +pub const ERROR_NO_MEDIA_IN_DRIVE: DWORD = 1112; +pub const ERROR_NO_UNICODE_TRANSLATION: DWORD = 1113; +pub const ERROR_DLL_INIT_FAILED: DWORD = 1114; +pub const ERROR_SHUTDOWN_IN_PROGRESS: DWORD = 1115; +pub const ERROR_NO_SHUTDOWN_IN_PROGRESS: DWORD = 1116; +pub const ERROR_IO_DEVICE: DWORD = 1117; +pub const ERROR_SERIAL_NO_DEVICE: DWORD = 1118; +pub const ERROR_IRQ_BUSY: DWORD = 1119; +pub const ERROR_MORE_WRITES: DWORD = 1120; +pub const ERROR_COUNTER_TIMEOUT: DWORD = 1121; +pub const ERROR_FLOPPY_ID_MARK_NOT_FOUND: DWORD = 1122; +pub const ERROR_FLOPPY_WRONG_CYLINDER: DWORD = 1123; +pub const ERROR_FLOPPY_UNKNOWN_ERROR: DWORD = 1124; +pub const ERROR_FLOPPY_BAD_REGISTERS: DWORD = 1125; +pub const ERROR_DISK_RECALIBRATE_FAILED: DWORD = 1126; +pub const ERROR_DISK_OPERATION_FAILED: DWORD = 1127; +pub const ERROR_DISK_RESET_FAILED: DWORD = 1128; +pub const ERROR_EOM_OVERFLOW: DWORD = 1129; +pub const ERROR_NOT_ENOUGH_SERVER_MEMORY: DWORD = 1130; +pub const ERROR_POSSIBLE_DEADLOCK: DWORD = 1131; +pub const ERROR_MAPPED_ALIGNMENT: DWORD = 1132; +pub const ERROR_SET_POWER_STATE_VETOED: DWORD = 1140; +pub const ERROR_SET_POWER_STATE_FAILED: DWORD = 1141; +pub const ERROR_TOO_MANY_LINKS: DWORD = 1142; +pub const ERROR_OLD_WIN_VERSION: DWORD = 1150; +pub const ERROR_APP_WRONG_OS: DWORD = 1151; +pub const ERROR_SINGLE_INSTANCE_APP: DWORD = 1152; +pub const ERROR_RMODE_APP: DWORD = 1153; +pub const ERROR_INVALID_DLL: DWORD = 1154; +pub const ERROR_NO_ASSOCIATION: DWORD = 1155; +pub const ERROR_DDE_FAIL: DWORD = 1156; +pub const ERROR_DLL_NOT_FOUND: DWORD = 1157; +pub const ERROR_NO_MORE_USER_HANDLES: DWORD = 1158; +pub const ERROR_MESSAGE_SYNC_ONLY: DWORD = 1159; +pub const ERROR_SOURCE_ELEMENT_EMPTY: DWORD = 1160; +pub const ERROR_DESTINATION_ELEMENT_FULL: DWORD = 1161; +pub const ERROR_ILLEGAL_ELEMENT_ADDRESS: DWORD = 1162; +pub const ERROR_MAGAZINE_NOT_PRESENT: DWORD = 1163; +pub const ERROR_DEVICE_REINITIALIZATION_NEEDED: DWORD = 1164; +pub const ERROR_DEVICE_REQUIRES_CLEANING: DWORD = 1165; +pub const ERROR_DEVICE_DOOR_OPEN: DWORD = 1166; +pub const ERROR_DEVICE_NOT_CONNECTED: DWORD = 1167; +pub const ERROR_NOT_FOUND: DWORD = 1168; +pub const ERROR_NO_MATCH: DWORD = 1169; +pub const ERROR_SET_NOT_FOUND: DWORD = 1170; +pub const ERROR_POINT_NOT_FOUND: DWORD = 1171; +pub const ERROR_NO_TRACKING_SERVICE: DWORD = 1172; +pub const ERROR_NO_VOLUME_ID: DWORD = 1173; +pub const ERROR_UNABLE_TO_REMOVE_REPLACED: DWORD = 1175; +pub const ERROR_UNABLE_TO_MOVE_REPLACEMENT: DWORD = 1176; +pub const ERROR_UNABLE_TO_MOVE_REPLACEMENT_2: DWORD = 1177; +pub const ERROR_JOURNAL_DELETE_IN_PROGRESS: DWORD = 1178; +pub const ERROR_JOURNAL_NOT_ACTIVE: DWORD = 1179; +pub const ERROR_POTENTIAL_FILE_FOUND: DWORD = 1180; +pub const ERROR_JOURNAL_ENTRY_DELETED: DWORD = 1181; +pub const ERROR_BAD_DEVICE: DWORD = 1200; +pub const ERROR_CONNECTION_UNAVAIL: DWORD = 1201; +pub const ERROR_DEVICE_ALREADY_REMEMBERED: DWORD = 1202; +pub const ERROR_NO_NET_OR_BAD_PATH: DWORD = 1203; +pub const ERROR_BAD_PROVIDER: DWORD = 1204; +pub const ERROR_CANNOT_OPEN_PROFILE: DWORD = 1205; +pub const ERROR_BAD_PROFILE: DWORD = 1206; +pub const ERROR_NOT_CONTAINER: DWORD = 1207; +pub const ERROR_EXTENDED_ERROR: DWORD = 1208; +pub const ERROR_INVALID_GROUPNAME: DWORD = 1209; +pub const ERROR_INVALID_COMPUTERNAME: DWORD = 1210; +pub const ERROR_INVALID_EVENTNAME: DWORD = 1211; +pub const ERROR_INVALID_DOMAINNAME: DWORD = 1212; +pub const ERROR_INVALID_SERVICENAME: DWORD = 1213; +pub const ERROR_INVALID_NETNAME: DWORD = 1214; +pub const ERROR_INVALID_SHARENAME: DWORD = 1215; +pub const ERROR_INVALID_PASSWORDNAME: DWORD = 1216; +pub const ERROR_INVALID_MESSAGENAME: DWORD = 1217; +pub const ERROR_INVALID_MESSAGEDEST: DWORD = 1218; +pub const ERROR_SESSION_CREDENTIAL_CONFLICT: DWORD = 1219; +pub const ERROR_REMOTE_SESSION_LIMIT_EXCEEDED: DWORD = 1220; +pub const ERROR_DUP_DOMAINNAME: DWORD = 1221; +pub const ERROR_NO_NETWORK: DWORD = 1222; +pub const ERROR_CANCELLED: DWORD = 1223; +pub const ERROR_USER_MAPPED_FILE: DWORD = 1224; +pub const ERROR_CONNECTION_REFUSED: DWORD = 1225; +pub const ERROR_GRACEFUL_DISCONNECT: DWORD = 1226; +pub const ERROR_ADDRESS_ALREADY_ASSOCIATED: DWORD = 1227; +pub const ERROR_ADDRESS_NOT_ASSOCIATED: DWORD = 1228; +pub const ERROR_CONNECTION_INVALID: DWORD = 1229; +pub const ERROR_CONNECTION_ACTIVE: DWORD = 1230; +pub const ERROR_NETWORK_UNREACHABLE: DWORD = 1231; +pub const ERROR_HOST_UNREACHABLE: DWORD = 1232; +pub const ERROR_PROTOCOL_UNREACHABLE: DWORD = 1233; +pub const ERROR_PORT_UNREACHABLE: DWORD = 1234; +pub const ERROR_REQUEST_ABORTED: DWORD = 1235; +pub const ERROR_CONNECTION_ABORTED: DWORD = 1236; +pub const ERROR_RETRY: DWORD = 1237; +pub const ERROR_CONNECTION_COUNT_LIMIT: DWORD = 1238; +pub const ERROR_LOGIN_TIME_RESTRICTION: DWORD = 1239; +pub const ERROR_LOGIN_WKSTA_RESTRICTION: DWORD = 1240; +pub const ERROR_INCORRECT_ADDRESS: DWORD = 1241; +pub const ERROR_ALREADY_REGISTERED: DWORD = 1242; +pub const ERROR_SERVICE_NOT_FOUND: DWORD = 1243; +pub const ERROR_NOT_AUTHENTICATED: DWORD = 1244; +pub const ERROR_NOT_LOGGED_ON: DWORD = 1245; +pub const ERROR_CONTINUE: DWORD = 1246; +pub const ERROR_ALREADY_INITIALIZED: DWORD = 1247; +pub const ERROR_NO_MORE_DEVICES: DWORD = 1248; +pub const ERROR_NO_SUCH_SITE: DWORD = 1249; +pub const ERROR_DOMAIN_CONTROLLER_EXISTS: DWORD = 1250; +pub const ERROR_ONLY_IF_CONNECTED: DWORD = 1251; +pub const ERROR_OVERRIDE_NOCHANGES: DWORD = 1252; +pub const ERROR_BAD_USER_PROFILE: DWORD = 1253; +pub const ERROR_NOT_SUPPORTED_ON_SBS: DWORD = 1254; +pub const ERROR_SERVER_SHUTDOWN_IN_PROGRESS: DWORD = 1255; +pub const ERROR_HOST_DOWN: DWORD = 1256; +pub const ERROR_NON_ACCOUNT_SID: DWORD = 1257; +pub const ERROR_NON_DOMAIN_SID: DWORD = 1258; +pub const ERROR_APPHELP_BLOCK: DWORD = 1259; +pub const ERROR_ACCESS_DISABLED_BY_POLICY: DWORD = 1260; +pub const ERROR_REG_NAT_CONSUMPTION: DWORD = 1261; +pub const ERROR_CSCSHARE_OFFLINE: DWORD = 1262; +pub const ERROR_PKINIT_FAILURE: DWORD = 1263; +pub const ERROR_SMARTCARD_SUBSYSTEM_FAILURE: DWORD = 1264; +pub const ERROR_DOWNGRADE_DETECTED: DWORD = 1265; +pub const ERROR_MACHINE_LOCKED: DWORD = 1271; +pub const ERROR_CALLBACK_SUPPLIED_INVALID_DATA: DWORD = 1273; +pub const ERROR_SYNC_FOREGROUND_REFRESH_REQUIRED: DWORD = 1274; +pub const ERROR_DRIVER_BLOCKED: DWORD = 1275; +pub const ERROR_INVALID_IMPORT_OF_NON_DLL: DWORD = 1276; +pub const ERROR_ACCESS_DISABLED_WEBBLADE: DWORD = 1277; +pub const ERROR_ACCESS_DISABLED_WEBBLADE_TAMPER: DWORD = 1278; +pub const ERROR_RECOVERY_FAILURE: DWORD = 1279; +pub const ERROR_ALREADY_FIBER: DWORD = 1280; +pub const ERROR_ALREADY_THREAD: DWORD = 1281; +pub const ERROR_STACK_BUFFER_OVERRUN: DWORD = 1282; +pub const ERROR_PARAMETER_QUOTA_EXCEEDED: DWORD = 1283; +pub const ERROR_DEBUGGER_INACTIVE: DWORD = 1284; +pub const ERROR_DELAY_LOAD_FAILED: DWORD = 1285; +pub const ERROR_VDM_DISALLOWED: DWORD = 1286; +pub const ERROR_UNIDENTIFIED_ERROR: DWORD = 1287; +pub const ERROR_NOT_ALL_ASSIGNED: DWORD = 1300; +pub const ERROR_SOME_NOT_MAPPED: DWORD = 1301; +pub const ERROR_NO_QUOTAS_FOR_ACCOUNT: DWORD = 1302; +pub const ERROR_LOCAL_USER_SESSION_KEY: DWORD = 1303; +pub const ERROR_NULL_LM_PASSWORD: DWORD = 1304; +pub const ERROR_UNKNOWN_REVISION: DWORD = 1305; +pub const ERROR_REVISION_MISMATCH: DWORD = 1306; +pub const ERROR_INVALID_OWNER: DWORD = 1307; +pub const ERROR_INVALID_PRIMARY_GROUP: DWORD = 1308; +pub const ERROR_NO_IMPERSONATION_TOKEN: DWORD = 1309; +pub const ERROR_CANT_DISABLE_MANDATORY: DWORD = 1310; +pub const ERROR_NO_LOGON_SERVERS: DWORD = 1311; +pub const ERROR_NO_SUCH_LOGON_SESSION: DWORD = 1312; +pub const ERROR_NO_SUCH_PRIVILEGE: DWORD = 1313; +pub const ERROR_PRIVILEGE_NOT_HELD: DWORD = 1314; +pub const ERROR_INVALID_ACCOUNT_NAME: DWORD = 1315; +pub const ERROR_USER_EXISTS: DWORD = 1316; +pub const ERROR_NO_SUCH_USER: DWORD = 1317; +pub const ERROR_GROUP_EXISTS: DWORD = 1318; +pub const ERROR_NO_SUCH_GROUP: DWORD = 1319; +pub const ERROR_MEMBER_IN_GROUP: DWORD = 1320; +pub const ERROR_MEMBER_NOT_IN_GROUP: DWORD = 1321; +pub const ERROR_LAST_ADMIN: DWORD = 1322; +pub const ERROR_WRONG_PASSWORD: DWORD = 1323; +pub const ERROR_ILL_FORMED_PASSWORD: DWORD = 1324; +pub const ERROR_PASSWORD_RESTRICTION: DWORD = 1325; +pub const ERROR_LOGON_FAILURE: DWORD = 1326; +pub const ERROR_ACCOUNT_RESTRICTION: DWORD = 1327; +pub const ERROR_INVALID_LOGON_HOURS: DWORD = 1328; +pub const ERROR_INVALID_WORKSTATION: DWORD = 1329; +pub const ERROR_PASSWORD_EXPIRED: DWORD = 1330; +pub const ERROR_ACCOUNT_DISABLED: DWORD = 1331; +pub const ERROR_NONE_MAPPED: DWORD = 1332; +pub const ERROR_TOO_MANY_LUIDS_REQUESTED: DWORD = 1333; +pub const ERROR_LUIDS_EXHAUSTED: DWORD = 1334; +pub const ERROR_INVALID_SUB_AUTHORITY: DWORD = 1335; +pub const ERROR_INVALID_ACL: DWORD = 1336; +pub const ERROR_INVALID_SID: DWORD = 1337; +pub const ERROR_INVALID_SECURITY_DESCR: DWORD = 1338; +pub const ERROR_BAD_INHERITANCE_ACL: DWORD = 1340; +pub const ERROR_SERVER_DISABLED: DWORD = 1341; +pub const ERROR_SERVER_NOT_DISABLED: DWORD = 1342; +pub const ERROR_INVALID_ID_AUTHORITY: DWORD = 1343; +pub const ERROR_ALLOTTED_SPACE_EXCEEDED: DWORD = 1344; +pub const ERROR_INVALID_GROUP_ATTRIBUTES: DWORD = 1345; +pub const ERROR_BAD_IMPERSONATION_LEVEL: DWORD = 1346; +pub const ERROR_CANT_OPEN_ANONYMOUS: DWORD = 1347; +pub const ERROR_BAD_VALIDATION_CLASS: DWORD = 1348; +pub const ERROR_BAD_TOKEN_TYPE: DWORD = 1349; +pub const ERROR_NO_SECURITY_ON_OBJECT: DWORD = 1350; +pub const ERROR_CANT_ACCESS_DOMAIN_INFO: DWORD = 1351; +pub const ERROR_INVALID_SERVER_STATE: DWORD = 1352; +pub const ERROR_INVALID_DOMAIN_STATE: DWORD = 1353; +pub const ERROR_INVALID_DOMAIN_ROLE: DWORD = 1354; +pub const ERROR_NO_SUCH_DOMAIN: DWORD = 1355; +pub const ERROR_DOMAIN_EXISTS: DWORD = 1356; +pub const ERROR_DOMAIN_LIMIT_EXCEEDED: DWORD = 1357; +pub const ERROR_INTERNAL_DB_CORRUPTION: DWORD = 1358; +pub const ERROR_INTERNAL_ERROR: DWORD = 1359; +pub const ERROR_GENERIC_NOT_MAPPED: DWORD = 1360; +pub const ERROR_BAD_DESCRIPTOR_FORMAT: DWORD = 1361; +pub const ERROR_NOT_LOGON_PROCESS: DWORD = 1362; +pub const ERROR_LOGON_SESSION_EXISTS: DWORD = 1363; +pub const ERROR_NO_SUCH_PACKAGE: DWORD = 1364; +pub const ERROR_BAD_LOGON_SESSION_STATE: DWORD = 1365; +pub const ERROR_LOGON_SESSION_COLLISION: DWORD = 1366; +pub const ERROR_INVALID_LOGON_TYPE: DWORD = 1367; +pub const ERROR_CANNOT_IMPERSONATE: DWORD = 1368; +pub const ERROR_RXACT_INVALID_STATE: DWORD = 1369; +pub const ERROR_RXACT_COMMIT_FAILURE: DWORD = 1370; +pub const ERROR_SPECIAL_ACCOUNT: DWORD = 1371; +pub const ERROR_SPECIAL_GROUP: DWORD = 1372; +pub const ERROR_SPECIAL_USER: DWORD = 1373; +pub const ERROR_MEMBERS_PRIMARY_GROUP: DWORD = 1374; +pub const ERROR_TOKEN_ALREADY_IN_USE: DWORD = 1375; +pub const ERROR_NO_SUCH_ALIAS: DWORD = 1376; +pub const ERROR_MEMBER_NOT_IN_ALIAS: DWORD = 1377; +pub const ERROR_MEMBER_IN_ALIAS: DWORD = 1378; +pub const ERROR_ALIAS_EXISTS: DWORD = 1379; +pub const ERROR_LOGON_NOT_GRANTED: DWORD = 1380; +pub const ERROR_TOO_MANY_SECRETS: DWORD = 1381; +pub const ERROR_SECRET_TOO_LONG: DWORD = 1382; +pub const ERROR_INTERNAL_DB_ERROR: DWORD = 1383; +pub const ERROR_TOO_MANY_CONTEXT_IDS: DWORD = 1384; +pub const ERROR_LOGON_TYPE_NOT_GRANTED: DWORD = 1385; +pub const ERROR_NT_CROSS_ENCRYPTION_REQUIRED: DWORD = 1386; +pub const ERROR_NO_SUCH_MEMBER: DWORD = 1387; +pub const ERROR_INVALID_MEMBER: DWORD = 1388; +pub const ERROR_TOO_MANY_SIDS: DWORD = 1389; +pub const ERROR_LM_CROSS_ENCRYPTION_REQUIRED: DWORD = 1390; +pub const ERROR_NO_INHERITANCE: DWORD = 1391; +pub const ERROR_FILE_CORRUPT: DWORD = 1392; +pub const ERROR_DISK_CORRUPT: DWORD = 1393; +pub const ERROR_NO_USER_SESSION_KEY: DWORD = 1394; +pub const ERROR_LICENSE_QUOTA_EXCEEDED: DWORD = 1395; +pub const ERROR_WRONG_TARGET_NAME: DWORD = 1396; +pub const ERROR_MUTUAL_AUTH_FAILED: DWORD = 1397; +pub const ERROR_TIME_SKEW: DWORD = 1398; +pub const ERROR_CURRENT_DOMAIN_NOT_ALLOWED: DWORD = 1399; +pub const ERROR_INVALID_WINDOW_HANDLE: DWORD = 1400; +pub const ERROR_INVALID_MENU_HANDLE: DWORD = 1401; +pub const ERROR_INVALID_CURSOR_HANDLE: DWORD = 1402; +pub const ERROR_INVALID_ACCEL_HANDLE: DWORD = 1403; +pub const ERROR_INVALID_HOOK_HANDLE: DWORD = 1404; +pub const ERROR_INVALID_DWP_HANDLE: DWORD = 1405; +pub const ERROR_TLW_WITH_WSCHILD: DWORD = 1406; +pub const ERROR_CANNOT_FIND_WND_CLASS: DWORD = 1407; +pub const ERROR_WINDOW_OF_OTHER_THREAD: DWORD = 1408; +pub const ERROR_HOTKEY_ALREADY_REGISTERED: DWORD = 1409; +pub const ERROR_CLASS_ALREADY_EXISTS: DWORD = 1410; +pub const ERROR_CLASS_DOES_NOT_EXIST: DWORD = 1411; +pub const ERROR_CLASS_HAS_WINDOWS: DWORD = 1412; +pub const ERROR_INVALID_INDEX: DWORD = 1413; +pub const ERROR_INVALID_ICON_HANDLE: DWORD = 1414; +pub const ERROR_PRIVATE_DIALOG_INDEX: DWORD = 1415; +pub const ERROR_LISTBOX_ID_NOT_FOUND: DWORD = 1416; +pub const ERROR_NO_WILDCARD_CHARACTERS: DWORD = 1417; +pub const ERROR_CLIPBOARD_NOT_OPEN: DWORD = 1418; +pub const ERROR_HOTKEY_NOT_REGISTERED: DWORD = 1419; +pub const ERROR_WINDOW_NOT_DIALOG: DWORD = 1420; +pub const ERROR_CONTROL_ID_NOT_FOUND: DWORD = 1421; +pub const ERROR_INVALID_COMBOBOX_MESSAGE: DWORD = 1422; +pub const ERROR_WINDOW_NOT_COMBOBOX: DWORD = 1423; +pub const ERROR_INVALID_EDIT_HEIGHT: DWORD = 1424; +pub const ERROR_DC_NOT_FOUND: DWORD = 1425; +pub const ERROR_INVALID_HOOK_FILTER: DWORD = 1426; +pub const ERROR_INVALID_FILTER_PROC: DWORD = 1427; +pub const ERROR_HOOK_NEEDS_HMOD: DWORD = 1428; +pub const ERROR_GLOBAL_ONLY_HOOK: DWORD = 1429; +pub const ERROR_JOURNAL_HOOK_SET: DWORD = 1430; +pub const ERROR_HOOK_NOT_INSTALLED: DWORD = 1431; +pub const ERROR_INVALID_LB_MESSAGE: DWORD = 1432; +pub const ERROR_SETCOUNT_ON_BAD_LB: DWORD = 1433; +pub const ERROR_LB_WITHOUT_TABSTOPS: DWORD = 1434; +pub const ERROR_DESTROY_OBJECT_OF_OTHER_THREAD: DWORD = 1435; +pub const ERROR_CHILD_WINDOW_MENU: DWORD = 1436; +pub const ERROR_NO_SYSTEM_MENU: DWORD = 1437; +pub const ERROR_INVALID_MSGBOX_STYLE: DWORD = 1438; +pub const ERROR_INVALID_SPI_VALUE: DWORD = 1439; +pub const ERROR_SCREEN_ALREADY_LOCKED: DWORD = 1440; +pub const ERROR_HWNDS_HAVE_DIFF_PARENT: DWORD = 1441; +pub const ERROR_NOT_CHILD_WINDOW: DWORD = 1442; +pub const ERROR_INVALID_GW_COMMAND: DWORD = 1443; +pub const ERROR_INVALID_THREAD_ID: DWORD = 1444; +pub const ERROR_NON_MDICHILD_WINDOW: DWORD = 1445; +pub const ERROR_POPUP_ALREADY_ACTIVE: DWORD = 1446; +pub const ERROR_NO_SCROLLBARS: DWORD = 1447; +pub const ERROR_INVALID_SCROLLBAR_RANGE: DWORD = 1448; +pub const ERROR_INVALID_SHOWWIN_COMMAND: DWORD = 1449; +pub const ERROR_NO_SYSTEM_RESOURCES: DWORD = 1450; +pub const ERROR_NONPAGED_SYSTEM_RESOURCES: DWORD = 1451; +pub const ERROR_PAGED_SYSTEM_RESOURCES: DWORD = 1452; +pub const ERROR_WORKING_SET_QUOTA: DWORD = 1453; +pub const ERROR_PAGEFILE_QUOTA: DWORD = 1454; +pub const ERROR_COMMITMENT_LIMIT: DWORD = 1455; +pub const ERROR_MENU_ITEM_NOT_FOUND: DWORD = 1456; +pub const ERROR_INVALID_KEYBOARD_HANDLE: DWORD = 1457; +pub const ERROR_HOOK_TYPE_NOT_ALLOWED: DWORD = 1458; +pub const ERROR_REQUIRES_INTERACTIVE_WINDOWSTATION: DWORD = 1459; +pub const ERROR_TIMEOUT: DWORD = 1460; +pub const ERROR_INVALID_MONITOR_HANDLE: DWORD = 1461; +pub const ERROR_INCORRECT_SIZE: DWORD = 1462; +pub const ERROR_SYMLINK_CLASS_DISABLED: DWORD = 1463; +pub const ERROR_SYMLINK_NOT_SUPPORTED: DWORD = 1464; +pub const ERROR_XML_PARSE_ERROR: DWORD = 1465; +pub const ERROR_XMLDSIG_ERROR: DWORD = 1466; +pub const ERROR_RESTART_APPLICATION: DWORD = 1467; +pub const ERROR_WRONG_COMPARTMENT: DWORD = 1468; +pub const ERROR_AUTHIP_FAILURE: DWORD = 1469; +pub const ERROR_NO_NVRAM_RESOURCES: DWORD = 1470; +pub const ERROR_NOT_GUI_PROCESS: DWORD = 1471; +pub const ERROR_EVENTLOG_FILE_CORRUPT: DWORD = 1500; +pub const ERROR_EVENTLOG_CANT_START: DWORD = 1501; +pub const ERROR_LOG_FILE_FULL: DWORD = 1502; +pub const ERROR_EVENTLOG_FILE_CHANGED: DWORD = 1503; +pub const ERROR_INSTALL_SERVICE_FAILURE: DWORD = 1601; +pub const ERROR_INSTALL_USEREXIT: DWORD = 1602; +pub const ERROR_INSTALL_FAILURE: DWORD = 1603; +pub const ERROR_INSTALL_SUSPEND: DWORD = 1604; +pub const ERROR_UNKNOWN_PRODUCT: DWORD = 1605; +pub const ERROR_UNKNOWN_FEATURE: DWORD = 1606; +pub const ERROR_UNKNOWN_COMPONENT: DWORD = 1607; +pub const ERROR_UNKNOWN_PROPERTY: DWORD = 1608; +pub const ERROR_INVALID_HANDLE_STATE: DWORD = 1609; +pub const ERROR_BAD_CONFIGURATION: DWORD = 1610; +pub const ERROR_INDEX_ABSENT: DWORD = 1611; +pub const ERROR_INSTALL_SOURCE_ABSENT: DWORD = 1612; +pub const ERROR_INSTALL_PACKAGE_VERSION: DWORD = 1613; +pub const ERROR_PRODUCT_UNINSTALLED: DWORD = 1614; +pub const ERROR_BAD_QUERY_SYNTAX: DWORD = 1615; +pub const ERROR_INVALID_FIELD: DWORD = 1616; +pub const ERROR_DEVICE_REMOVED: DWORD = 1617; +pub const ERROR_INSTALL_ALREADY_RUNNING: DWORD = 1618; +pub const ERROR_INSTALL_PACKAGE_OPEN_FAILED: DWORD = 1619; +pub const ERROR_INSTALL_PACKAGE_INVALID: DWORD = 1620; +pub const ERROR_INSTALL_UI_FAILURE: DWORD = 1621; +pub const ERROR_INSTALL_LOG_FAILURE: DWORD = 1622; +pub const ERROR_INSTALL_LANGUAGE_UNSUPPORTED: DWORD = 1623; +pub const ERROR_INSTALL_TRANSFORM_FAILURE: DWORD = 1624; +pub const ERROR_INSTALL_PACKAGE_REJECTED: DWORD = 1625; +pub const ERROR_FUNCTION_NOT_CALLED: DWORD = 1626; +pub const ERROR_FUNCTION_FAILED: DWORD = 1627; +pub const ERROR_INVALID_TABLE: DWORD = 1628; +pub const ERROR_DATATYPE_MISMATCH: DWORD = 1629; +pub const ERROR_UNSUPPORTED_TYPE: DWORD = 1630; +pub const ERROR_CREATE_FAILED: DWORD = 1631; +pub const ERROR_INSTALL_TEMP_UNWRITABLE: DWORD = 1632; +pub const ERROR_INSTALL_PLATFORM_UNSUPPORTED: DWORD = 1633; +pub const ERROR_INSTALL_NOTUSED: DWORD = 1634; +pub const ERROR_PATCH_PACKAGE_OPEN_FAILED: DWORD = 1635; +pub const ERROR_PATCH_PACKAGE_INVALID: DWORD = 1636; +pub const ERROR_PATCH_PACKAGE_UNSUPPORTED: DWORD = 1637; +pub const ERROR_PRODUCT_VERSION: DWORD = 1638; +pub const ERROR_INVALID_COMMAND_LINE: DWORD = 1639; +pub const ERROR_INSTALL_REMOTE_DISALLOWED: DWORD = 1640; +pub const ERROR_SUCCESS_REBOOT_INITIATED: DWORD = 1641; +pub const ERROR_PATCH_TARGET_NOT_FOUND: DWORD = 1642; +pub const ERROR_PATCH_PACKAGE_REJECTED: DWORD = 1643; +pub const ERROR_INSTALL_TRANSFORM_REJECTED: DWORD = 1644; +pub const ERROR_INSTALL_REMOTE_PROHIBITED: DWORD = 1645; +pub const ERROR_INVALID_USER_BUFFER: DWORD = 1784; +pub const ERROR_UNRECOGNIZED_MEDIA: DWORD = 1785; +pub const ERROR_NO_TRUST_LSA_SECRET: DWORD = 1786; +pub const ERROR_NO_TRUST_SAM_ACCOUNT: DWORD = 1787; +pub const ERROR_TRUSTED_DOMAIN_FAILURE: DWORD = 1788; +pub const ERROR_TRUSTED_RELATIONSHIP_FAILURE: DWORD = 1789; +pub const ERROR_TRUST_FAILURE: DWORD = 1790; +pub const ERROR_NETLOGON_NOT_STARTED: DWORD = 1792; +pub const ERROR_ACCOUNT_EXPIRED: DWORD = 1793; +pub const ERROR_REDIRECTOR_HAS_OPEN_HANDLES: DWORD = 1794; +pub const ERROR_PRINTER_DRIVER_ALREADY_INSTALLED: DWORD = 1795; +pub const ERROR_UNKNOWN_PORT: DWORD = 1796; +pub const ERROR_UNKNOWN_PRINTER_DRIVER: DWORD = 1797; +pub const ERROR_UNKNOWN_PRINTPROCESSOR: DWORD = 1798; +pub const ERROR_INVALID_SEPARATOR_FILE: DWORD = 1799; +pub const ERROR_INVALID_PRIORITY: DWORD = 1800; +pub const ERROR_INVALID_PRINTER_NAME: DWORD = 1801; +pub const ERROR_PRINTER_ALREADY_EXISTS: DWORD = 1802; +pub const ERROR_INVALID_PRINTER_COMMAND: DWORD = 1803; +pub const ERROR_INVALID_DATATYPE: DWORD = 1804; +pub const ERROR_INVALID_ENVIRONMENT: DWORD = 1805; +pub const ERROR_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT: DWORD = 1807; +pub const ERROR_NOLOGON_WORKSTATION_TRUST_ACCOUNT: DWORD = 1808; +pub const ERROR_NOLOGON_SERVER_TRUST_ACCOUNT: DWORD = 1809; +pub const ERROR_DOMAIN_TRUST_INCONSISTENT: DWORD = 1810; +pub const ERROR_SERVER_HAS_OPEN_HANDLES: DWORD = 1811; +pub const ERROR_RESOURCE_DATA_NOT_FOUND: DWORD = 1812; +pub const ERROR_RESOURCE_TYPE_NOT_FOUND: DWORD = 1813; +pub const ERROR_RESOURCE_NAME_NOT_FOUND: DWORD = 1814; +pub const ERROR_RESOURCE_LANG_NOT_FOUND: DWORD = 1815; +pub const ERROR_NOT_ENOUGH_QUOTA: DWORD = 1816; +pub const ERROR_INVALID_TIME: DWORD = 1901; +pub const ERROR_INVALID_FORM_NAME: DWORD = 1902; +pub const ERROR_INVALID_FORM_SIZE: DWORD = 1903; +pub const ERROR_ALREADY_WAITING: DWORD = 1904; +pub const ERROR_PRINTER_DELETED: DWORD = 1905; +pub const ERROR_INVALID_PRINTER_STATE: DWORD = 1906; +pub const ERROR_PASSWORD_MUST_CHANGE: DWORD = 1907; +pub const ERROR_DOMAIN_CONTROLLER_NOT_FOUND: DWORD = 1908; +pub const ERROR_ACCOUNT_LOCKED_OUT: DWORD = 1909; +pub const ERROR_NO_SITENAME: DWORD = 1919; +pub const ERROR_CANT_ACCESS_FILE: DWORD = 1920; +pub const ERROR_CANT_RESOLVE_FILENAME: DWORD = 1921; +pub const ERROR_KM_DRIVER_BLOCKED: DWORD = 1930; +pub const ERROR_CONTEXT_EXPIRED: DWORD = 1931; +pub const ERROR_PER_USER_TRUST_QUOTA_EXCEEDED: DWORD = 1932; +pub const ERROR_ALL_USER_TRUST_QUOTA_EXCEEDED: DWORD = 1933; +pub const ERROR_USER_DELETE_TRUST_QUOTA_EXCEEDED: DWORD = 1934; +pub const ERROR_AUTHENTICATION_FIREWALL_FAILED: DWORD = 1935; +pub const ERROR_REMOTE_PRINT_CONNECTIONS_BLOCKED: DWORD = 1936; +pub const ERROR_INVALID_PIXEL_FORMAT: DWORD = 2000; +pub const ERROR_BAD_DRIVER: DWORD = 2001; +pub const ERROR_INVALID_WINDOW_STYLE: DWORD = 2002; +pub const ERROR_METAFILE_NOT_SUPPORTED: DWORD = 2003; +pub const ERROR_TRANSFORM_NOT_SUPPORTED: DWORD = 2004; +pub const ERROR_CLIPPING_NOT_SUPPORTED: DWORD = 2005; +pub const ERROR_INVALID_CMM: DWORD = 2010; +pub const ERROR_INVALID_PROFILE: DWORD = 2011; +pub const ERROR_TAG_NOT_FOUND: DWORD = 2012; +pub const ERROR_TAG_NOT_PRESENT: DWORD = 2013; +pub const ERROR_DUPLICATE_TAG: DWORD = 2014; +pub const ERROR_PROFILE_NOT_ASSOCIATED_WITH_DEVICE: DWORD = 2015; +pub const ERROR_PROFILE_NOT_FOUND: DWORD = 2016; +pub const ERROR_INVALID_COLORSPACE: DWORD = 2017; +pub const ERROR_ICM_NOT_ENABLED: DWORD = 2018; +pub const ERROR_DELETING_ICM_XFORM: DWORD = 2019; +pub const ERROR_INVALID_TRANSFORM: DWORD = 2020; +pub const ERROR_COLORSPACE_MISMATCH: DWORD = 2021; +pub const ERROR_INVALID_COLORINDEX: DWORD = 2022; +pub const ERROR_CONNECTED_OTHER_PASSWORD: DWORD = 2108; +pub const ERROR_CONNECTED_OTHER_PASSWORD_DEFAULT: DWORD = 2109; +pub const ERROR_BAD_USERNAME: DWORD = 2202; +pub const ERROR_NOT_CONNECTED: DWORD = 2250; +pub const ERROR_OPEN_FILES: DWORD = 2401; +pub const ERROR_ACTIVE_CONNECTIONS: DWORD = 2402; +pub const ERROR_DEVICE_IN_USE: DWORD = 2404; +pub const ERROR_UNKNOWN_PRINT_MONITOR: DWORD = 3000; +pub const ERROR_PRINTER_DRIVER_IN_USE: DWORD = 3001; +pub const ERROR_SPOOL_FILE_NOT_FOUND: DWORD = 3002; +pub const ERROR_SPL_NO_STARTDOC: DWORD = 3003; +pub const ERROR_SPL_NO_ADDJOB: DWORD = 3004; +pub const ERROR_PRINT_PROCESSOR_ALREADY_INSTALLED: DWORD = 3005; +pub const ERROR_PRINT_MONITOR_ALREADY_INSTALLED: DWORD = 3006; +pub const ERROR_INVALID_PRINT_MONITOR: DWORD = 3007; +pub const ERROR_PRINT_MONITOR_IN_USE: DWORD = 3008; +pub const ERROR_PRINTER_HAS_JOBS_QUEUED: DWORD = 3009; +pub const ERROR_SUCCESS_REBOOT_REQUIRED: DWORD = 3010; +pub const ERROR_SUCCESS_RESTART_REQUIRED: DWORD = 3011; +pub const ERROR_PRINTER_NOT_FOUND: DWORD = 3012; +pub const ERROR_PRINTER_DRIVER_WARNED: DWORD = 3013; +pub const ERROR_PRINTER_DRIVER_BLOCKED: DWORD = 3014; +pub const ERROR_WINS_INTERNAL: DWORD = 4000; +pub const ERROR_CAN_NOT_DEL_LOCAL_WINS: DWORD = 4001; +pub const ERROR_STATIC_INIT: DWORD = 4002; +pub const ERROR_INC_BACKUP: DWORD = 4003; +pub const ERROR_FULL_BACKUP: DWORD = 4004; +pub const ERROR_REC_NON_EXISTENT: DWORD = 4005; +pub const ERROR_RPL_NOT_ALLOWED: DWORD = 4006; +pub const ERROR_DHCP_ADDRESS_CONFLICT: DWORD = 4100; +pub const ERROR_WMI_GUID_NOT_FOUND: DWORD = 4200; +pub const ERROR_WMI_INSTANCE_NOT_FOUND: DWORD = 4201; +pub const ERROR_WMI_ITEMID_NOT_FOUND: DWORD = 4202; +pub const ERROR_WMI_TRY_AGAIN: DWORD = 4203; +pub const ERROR_WMI_DP_NOT_FOUND: DWORD = 4204; +pub const ERROR_WMI_UNRESOLVED_INSTANCE_REF: DWORD = 4205; +pub const ERROR_WMI_ALREADY_ENABLED: DWORD = 4206; +pub const ERROR_WMI_GUID_DISCONNECTED: DWORD = 4207; +pub const ERROR_WMI_SERVER_UNAVAILABLE: DWORD = 4208; +pub const ERROR_WMI_DP_FAILED: DWORD = 4209; +pub const ERROR_WMI_INVALID_MOF: DWORD = 4210; +pub const ERROR_WMI_INVALID_REGINFO: DWORD = 4211; +pub const ERROR_WMI_ALREADY_DISABLED: DWORD = 4212; +pub const ERROR_WMI_READ_ONLY: DWORD = 4213; +pub const ERROR_WMI_SET_FAILURE: DWORD = 4214; +pub const ERROR_INVALID_MEDIA: DWORD = 4300; +pub const ERROR_INVALID_LIBRARY: DWORD = 4301; +pub const ERROR_INVALID_MEDIA_POOL: DWORD = 4302; +pub const ERROR_DRIVE_MEDIA_MISMATCH: DWORD = 4303; +pub const ERROR_MEDIA_OFFLINE: DWORD = 4304; +pub const ERROR_LIBRARY_OFFLINE: DWORD = 4305; +pub const ERROR_EMPTY: DWORD = 4306; +pub const ERROR_NOT_EMPTY: DWORD = 4307; +pub const ERROR_MEDIA_UNAVAILABLE: DWORD = 4308; +pub const ERROR_RESOURCE_DISABLED: DWORD = 4309; +pub const ERROR_INVALID_CLEANER: DWORD = 4310; +pub const ERROR_UNABLE_TO_CLEAN: DWORD = 4311; +pub const ERROR_OBJECT_NOT_FOUND: DWORD = 4312; +pub const ERROR_DATABASE_FAILURE: DWORD = 4313; +pub const ERROR_DATABASE_FULL: DWORD = 4314; +pub const ERROR_MEDIA_INCOMPATIBLE: DWORD = 4315; +pub const ERROR_RESOURCE_NOT_PRESENT: DWORD = 4316; +pub const ERROR_INVALID_OPERATION: DWORD = 4317; +pub const ERROR_MEDIA_NOT_AVAILABLE: DWORD = 4318; +pub const ERROR_DEVICE_NOT_AVAILABLE: DWORD = 4319; +pub const ERROR_REQUEST_REFUSED: DWORD = 4320; +pub const ERROR_INVALID_DRIVE_OBJECT: DWORD = 4321; +pub const ERROR_LIBRARY_FULL: DWORD = 4322; +pub const ERROR_MEDIUM_NOT_ACCESSIBLE: DWORD = 4323; +pub const ERROR_UNABLE_TO_LOAD_MEDIUM: DWORD = 4324; +pub const ERROR_UNABLE_TO_INVENTORY_DRIVE: DWORD = 4325; +pub const ERROR_UNABLE_TO_INVENTORY_SLOT: DWORD = 4326; +pub const ERROR_UNABLE_TO_INVENTORY_TRANSPORT: DWORD = 4327; +pub const ERROR_TRANSPORT_FULL: DWORD = 4328; +pub const ERROR_CONTROLLING_IEPORT: DWORD = 4329; +pub const ERROR_UNABLE_TO_EJECT_MOUNTED_MEDIA: DWORD = 4330; +pub const ERROR_CLEANER_SLOT_SET: DWORD = 4331; +pub const ERROR_CLEANER_SLOT_NOT_SET: DWORD = 4332; +pub const ERROR_CLEANER_CARTRIDGE_SPENT: DWORD = 4333; +pub const ERROR_UNEXPECTED_OMID: DWORD = 4334; +pub const ERROR_CANT_DELETE_LAST_ITEM: DWORD = 4335; +pub const ERROR_MESSAGE_EXCEEDS_MAX_SIZE: DWORD = 4336; +pub const ERROR_VOLUME_CONTAINS_SYS_FILES: DWORD = 4337; +pub const ERROR_INDIGENOUS_TYPE: DWORD = 4338; +pub const ERROR_NO_SUPPORTING_DRIVES: DWORD = 4339; +pub const ERROR_CLEANER_CARTRIDGE_INSTALLED: DWORD = 4340; +pub const ERROR_IEPORT_FULL: DWORD = 4341; +pub const ERROR_FILE_OFFLINE: DWORD = 4350; +pub const ERROR_REMOTE_STORAGE_NOT_ACTIVE: DWORD = 4351; +pub const ERROR_REMOTE_STORAGE_MEDIA_ERROR: DWORD = 4352; +pub const ERROR_NOT_A_REPARSE_POINT: DWORD = 4390; +pub const ERROR_REPARSE_ATTRIBUTE_CONFLICT: DWORD = 4391; +pub const ERROR_INVALID_REPARSE_DATA: DWORD = 4392; +pub const ERROR_REPARSE_TAG_INVALID: DWORD = 4393; +pub const ERROR_REPARSE_TAG_MISMATCH: DWORD = 4394; +pub const ERROR_VOLUME_NOT_SIS_ENABLED: DWORD = 4500; +pub const ERROR_DEPENDENT_RESOURCE_EXISTS: DWORD = 5001; +pub const ERROR_DEPENDENCY_NOT_FOUND: DWORD = 5002; +pub const ERROR_DEPENDENCY_ALREADY_EXISTS: DWORD = 5003; +pub const ERROR_RESOURCE_NOT_ONLINE: DWORD = 5004; +pub const ERROR_HOST_NODE_NOT_AVAILABLE: DWORD = 5005; +pub const ERROR_RESOURCE_NOT_AVAILABLE: DWORD = 5006; +pub const ERROR_RESOURCE_NOT_FOUND: DWORD = 5007; +pub const ERROR_SHUTDOWN_CLUSTER: DWORD = 5008; +pub const ERROR_CANT_EVICT_ACTIVE_NODE: DWORD = 5009; +pub const ERROR_OBJECT_ALREADY_EXISTS: DWORD = 5010; +pub const ERROR_OBJECT_IN_LIST: DWORD = 5011; +pub const ERROR_GROUP_NOT_AVAILABLE: DWORD = 5012; +pub const ERROR_GROUP_NOT_FOUND: DWORD = 5013; +pub const ERROR_GROUP_NOT_ONLINE: DWORD = 5014; +pub const ERROR_HOST_NODE_NOT_RESOURCE_OWNER: DWORD = 5015; +pub const ERROR_HOST_NODE_NOT_GROUP_OWNER: DWORD = 5016; +pub const ERROR_RESMON_CREATE_FAILED: DWORD = 5017; +pub const ERROR_RESMON_ONLINE_FAILED: DWORD = 5018; +pub const ERROR_RESOURCE_ONLINE: DWORD = 5019; +pub const ERROR_QUORUM_RESOURCE: DWORD = 5020; +pub const ERROR_NOT_QUORUM_CAPABLE: DWORD = 5021; +pub const ERROR_CLUSTER_SHUTTING_DOWN: DWORD = 5022; +pub const ERROR_INVALID_STATE: DWORD = 5023; +pub const ERROR_RESOURCE_PROPERTIES_STORED: DWORD = 5024; +pub const ERROR_NOT_QUORUM_CLASS: DWORD = 5025; +pub const ERROR_CORE_RESOURCE: DWORD = 5026; +pub const ERROR_QUORUM_RESOURCE_ONLINE_FAILED: DWORD = 5027; +pub const ERROR_QUORUMLOG_OPEN_FAILED: DWORD = 5028; +pub const ERROR_CLUSTERLOG_CORRUPT: DWORD = 5029; +pub const ERROR_CLUSTERLOG_RECORD_EXCEEDS_MAXSIZE: DWORD = 5030; +pub const ERROR_CLUSTERLOG_EXCEEDS_MAXSIZE: DWORD = 5031; +pub const ERROR_CLUSTERLOG_CHKPOINT_NOT_FOUND: DWORD = 5032; +pub const ERROR_CLUSTERLOG_NOT_ENOUGH_SPACE: DWORD = 5033; +pub const ERROR_QUORUM_OWNER_ALIVE: DWORD = 5034; +pub const ERROR_NETWORK_NOT_AVAILABLE: DWORD = 5035; +pub const ERROR_NODE_NOT_AVAILABLE: DWORD = 5036; +pub const ERROR_ALL_NODES_NOT_AVAILABLE: DWORD = 5037; +pub const ERROR_RESOURCE_FAILED: DWORD = 5038; +pub const ERROR_CLUSTER_INVALID_NODE: DWORD = 5039; +pub const ERROR_CLUSTER_NODE_EXISTS: DWORD = 5040; +pub const ERROR_CLUSTER_JOIN_IN_PROGRESS: DWORD = 5041; +pub const ERROR_CLUSTER_NODE_NOT_FOUND: DWORD = 5042; +pub const ERROR_CLUSTER_LOCAL_NODE_NOT_FOUND: DWORD = 5043; +pub const ERROR_CLUSTER_NETWORK_EXISTS: DWORD = 5044; +pub const ERROR_CLUSTER_NETWORK_NOT_FOUND: DWORD = 5045; +pub const ERROR_CLUSTER_NETINTERFACE_EXISTS: DWORD = 5046; +pub const ERROR_CLUSTER_NETINTERFACE_NOT_FOUND: DWORD = 5047; +pub const ERROR_CLUSTER_INVALID_REQUEST: DWORD = 5048; +pub const ERROR_CLUSTER_INVALID_NETWORK_PROVIDER: DWORD = 5049; +pub const ERROR_CLUSTER_NODE_DOWN: DWORD = 5050; +pub const ERROR_CLUSTER_NODE_UNREACHABLE: DWORD = 5051; +pub const ERROR_CLUSTER_NODE_NOT_MEMBER: DWORD = 5052; +pub const ERROR_CLUSTER_JOIN_NOT_IN_PROGRESS: DWORD = 5053; +pub const ERROR_CLUSTER_INVALID_NETWORK: DWORD = 5054; +pub const ERROR_CLUSTER_NODE_UP: DWORD = 5056; +pub const ERROR_CLUSTER_IPADDR_IN_USE: DWORD = 5057; +pub const ERROR_CLUSTER_NODE_NOT_PAUSED: DWORD = 5058; +pub const ERROR_CLUSTER_NO_SECURITY_CONTEXT: DWORD = 5059; +pub const ERROR_CLUSTER_NETWORK_NOT_INTERNAL: DWORD = 5060; +pub const ERROR_CLUSTER_NODE_ALREADY_UP: DWORD = 5061; +pub const ERROR_CLUSTER_NODE_ALREADY_DOWN: DWORD = 5062; +pub const ERROR_CLUSTER_NETWORK_ALREADY_ONLINE: DWORD = 5063; +pub const ERROR_CLUSTER_NETWORK_ALREADY_OFFLINE: DWORD = 5064; +pub const ERROR_CLUSTER_NODE_ALREADY_MEMBER: DWORD = 5065; +pub const ERROR_CLUSTER_LAST_INTERNAL_NETWORK: DWORD = 5066; +pub const ERROR_CLUSTER_NETWORK_HAS_DEPENDENTS: DWORD = 5067; +pub const ERROR_INVALID_OPERATION_ON_QUORUM: DWORD = 5068; +pub const ERROR_DEPENDENCY_NOT_ALLOWED: DWORD = 5069; +pub const ERROR_CLUSTER_NODE_PAUSED: DWORD = 5070; +pub const ERROR_NODE_CANT_HOST_RESOURCE: DWORD = 5071; +pub const ERROR_CLUSTER_NODE_NOT_READY: DWORD = 5072; +pub const ERROR_CLUSTER_NODE_SHUTTING_DOWN: DWORD = 5073; +pub const ERROR_CLUSTER_JOIN_ABORTED: DWORD = 5074; +pub const ERROR_CLUSTER_INCOMPATIBLE_VERSIONS: DWORD = 5075; +pub const ERROR_CLUSTER_MAXNUM_OF_RESOURCES_EXCEEDED: DWORD = 5076; +pub const ERROR_CLUSTER_SYSTEM_CONFIG_CHANGED: DWORD = 5077; +pub const ERROR_CLUSTER_RESOURCE_TYPE_NOT_FOUND: DWORD = 5078; +pub const ERROR_CLUSTER_RESTYPE_NOT_SUPPORTED: DWORD = 5079; +pub const ERROR_CLUSTER_RESNAME_NOT_FOUND: DWORD = 5080; +pub const ERROR_CLUSTER_NO_RPC_PACKAGES_REGISTERED: DWORD = 5081; +pub const ERROR_CLUSTER_OWNER_NOT_IN_PREFLIST: DWORD = 5082; +pub const ERROR_CLUSTER_DATABASE_SEQMISMATCH: DWORD = 5083; +pub const ERROR_RESMON_INVALID_STATE: DWORD = 5084; +pub const ERROR_CLUSTER_GUM_NOT_LOCKER: DWORD = 5085; +pub const ERROR_QUORUM_DISK_NOT_FOUND: DWORD = 5086; +pub const ERROR_DATABASE_BACKUP_CORRUPT: DWORD = 5087; +pub const ERROR_CLUSTER_NODE_ALREADY_HAS_DFS_ROOT: DWORD = 5088; +pub const ERROR_RESOURCE_PROPERTY_UNCHANGEABLE: DWORD = 5089; +pub const ERROR_CLUSTER_MEMBERSHIP_INVALID_STATE: DWORD = 5890; +pub const ERROR_CLUSTER_QUORUMLOG_NOT_FOUND: DWORD = 5891; +pub const ERROR_CLUSTER_MEMBERSHIP_HALT: DWORD = 5892; +pub const ERROR_CLUSTER_INSTANCE_ID_MISMATCH: DWORD = 5893; +pub const ERROR_CLUSTER_NETWORK_NOT_FOUND_FOR_IP: DWORD = 5894; +pub const ERROR_CLUSTER_PROPERTY_DATA_TYPE_MISMATCH: DWORD = 5895; +pub const ERROR_CLUSTER_EVICT_WITHOUT_CLEANUP: DWORD = 5896; +pub const ERROR_CLUSTER_PARAMETER_MISMATCH: DWORD = 5897; +pub const ERROR_NODE_CANNOT_BE_CLUSTERED: DWORD = 5898; +pub const ERROR_CLUSTER_WRONG_OS_VERSION: DWORD = 5899; +pub const ERROR_CLUSTER_CANT_CREATE_DUP_CLUSTER_NAME: DWORD = 5900; +pub const ERROR_CLUSCFG_ALREADY_COMMITTED: DWORD = 5901; +pub const ERROR_CLUSCFG_ROLLBACK_FAILED: DWORD = 5902; +pub const ERROR_CLUSCFG_SYSTEM_DISK_DRIVE_LETTER_CONFLICT: DWORD = 5903; +pub const ERROR_CLUSTER_OLD_VERSION: DWORD = 5904; +pub const ERROR_CLUSTER_MISMATCHED_COMPUTER_ACCT_NAME: DWORD = 5905; +pub const ERROR_ENCRYPTION_FAILED: DWORD = 6000; +pub const ERROR_DECRYPTION_FAILED: DWORD = 6001; +pub const ERROR_FILE_ENCRYPTED: DWORD = 6002; +pub const ERROR_NO_RECOVERY_POLICY: DWORD = 6003; +pub const ERROR_NO_EFS: DWORD = 6004; +pub const ERROR_WRONG_EFS: DWORD = 6005; +pub const ERROR_NO_USER_KEYS: DWORD = 6006; +pub const ERROR_FILE_NOT_ENCRYPTED: DWORD = 6007; +pub const ERROR_NOT_EXPORT_FORMAT: DWORD = 6008; +pub const ERROR_FILE_READ_ONLY: DWORD = 6009; +pub const ERROR_DIR_EFS_DISALLOWED: DWORD = 6010; +pub const ERROR_EFS_SERVER_NOT_TRUSTED: DWORD = 6011; +pub const ERROR_BAD_RECOVERY_POLICY: DWORD = 6012; +pub const ERROR_EFS_ALG_BLOB_TOO_BIG: DWORD = 6013; +pub const ERROR_VOLUME_NOT_SUPPORT_EFS: DWORD = 6014; +pub const ERROR_EFS_DISABLED: DWORD = 6015; +pub const ERROR_EFS_VERSION_NOT_SUPPORT: DWORD = 6016; +pub const ERROR_NO_BROWSER_SERVERS_FOUND: DWORD = 6118; +pub const ERROR_CTX_WINSTATION_NAME_INVALID: DWORD = 7001; +pub const ERROR_CTX_INVALID_PD: DWORD = 7002; +pub const ERROR_CTX_PD_NOT_FOUND: DWORD = 7003; +pub const ERROR_CTX_WD_NOT_FOUND: DWORD = 7004; +pub const ERROR_CTX_CANNOT_MAKE_EVENTLOG_ENTRY: DWORD = 7005; +pub const ERROR_CTX_SERVICE_NAME_COLLISION: DWORD = 7006; +pub const ERROR_CTX_CLOSE_PENDING: DWORD = 7007; +pub const ERROR_CTX_NO_OUTBUF: DWORD = 7008; +pub const ERROR_CTX_MODEM_INF_NOT_FOUND: DWORD = 7009; +pub const ERROR_CTX_INVALID_MODEMNAME: DWORD = 7010; +pub const ERROR_CTX_MODEM_RESPONSE_ERROR: DWORD = 7011; +pub const ERROR_CTX_MODEM_RESPONSE_TIMEOUT: DWORD = 7012; +pub const ERROR_CTX_MODEM_RESPONSE_NO_CARRIER: DWORD = 7013; +pub const ERROR_CTX_MODEM_RESPONSE_NO_DIALTONE: DWORD = 7014; +pub const ERROR_CTX_MODEM_RESPONSE_BUSY: DWORD = 7015; +pub const ERROR_CTX_MODEM_RESPONSE_VOICE: DWORD = 7016; +pub const ERROR_CTX_TD_ERROR: DWORD = 7017; +pub const ERROR_CTX_WINSTATION_NOT_FOUND: DWORD = 7022; +pub const ERROR_CTX_WINSTATION_ALREADY_EXISTS: DWORD = 7023; +pub const ERROR_CTX_WINSTATION_BUSY: DWORD = 7024; +pub const ERROR_CTX_BAD_VIDEO_MODE: DWORD = 7025; +pub const ERROR_CTX_GRAPHICS_INVALID: DWORD = 7035; +pub const ERROR_CTX_LOGON_DISABLED: DWORD = 7037; +pub const ERROR_CTX_NOT_CONSOLE: DWORD = 7038; +pub const ERROR_CTX_CLIENT_QUERY_TIMEOUT: DWORD = 7040; +pub const ERROR_CTX_CONSOLE_DISCONNECT: DWORD = 7041; +pub const ERROR_CTX_CONSOLE_CONNECT: DWORD = 7042; +pub const ERROR_CTX_SHADOW_DENIED: DWORD = 7044; +pub const ERROR_CTX_WINSTATION_ACCESS_DENIED: DWORD = 7045; +pub const ERROR_CTX_INVALID_WD: DWORD = 7049; +pub const ERROR_CTX_SHADOW_INVALID: DWORD = 7050; +pub const ERROR_CTX_SHADOW_DISABLED: DWORD = 7051; +pub const ERROR_CTX_CLIENT_LICENSE_IN_USE: DWORD = 7052; +pub const ERROR_CTX_CLIENT_LICENSE_NOT_SET: DWORD = 7053; +pub const ERROR_CTX_LICENSE_NOT_AVAILABLE: DWORD = 7054; +pub const ERROR_CTX_LICENSE_CLIENT_INVALID: DWORD = 7055; +pub const ERROR_CTX_LICENSE_EXPIRED: DWORD = 7056; +pub const ERROR_CTX_SHADOW_NOT_RUNNING: DWORD = 7057; +pub const ERROR_CTX_SHADOW_ENDED_BY_MODE_CHANGE: DWORD = 7058; +pub const ERROR_ACTIVATION_COUNT_EXCEEDED: DWORD = 7059; +pub const ERROR_DS_NOT_INSTALLED: DWORD = 8200; +pub const ERROR_DS_MEMBERSHIP_EVALUATED_LOCALLY: DWORD = 8201; +pub const ERROR_DS_NO_ATTRIBUTE_OR_VALUE: DWORD = 8202; +pub const ERROR_DS_INVALID_ATTRIBUTE_SYNTAX: DWORD = 8203; +pub const ERROR_DS_ATTRIBUTE_TYPE_UNDEFINED: DWORD = 8204; +pub const ERROR_DS_ATTRIBUTE_OR_VALUE_EXISTS: DWORD = 8205; +pub const ERROR_DS_BUSY: DWORD = 8206; +pub const ERROR_DS_UNAVAILABLE: DWORD = 8207; +pub const ERROR_DS_NO_RIDS_ALLOCATED: DWORD = 8208; +pub const ERROR_DS_NO_MORE_RIDS: DWORD = 8209; +pub const ERROR_DS_INCORRECT_ROLE_OWNER: DWORD = 8210; +pub const ERROR_DS_RIDMGR_INIT_ERROR: DWORD = 8211; +pub const ERROR_DS_OBJ_CLASS_VIOLATION: DWORD = 8212; +pub const ERROR_DS_CANT_ON_NON_LEAF: DWORD = 8213; +pub const ERROR_DS_CANT_ON_RDN: DWORD = 8214; +pub const ERROR_DS_CANT_MOD_OBJ_CLASS: DWORD = 8215; +pub const ERROR_DS_CROSS_DOM_MOVE_ERROR: DWORD = 8216; +pub const ERROR_DS_GC_NOT_AVAILABLE: DWORD = 8217; +pub const ERROR_SHARED_POLICY: DWORD = 8218; +pub const ERROR_POLICY_OBJECT_NOT_FOUND: DWORD = 8219; +pub const ERROR_POLICY_ONLY_IN_DS: DWORD = 8220; +pub const ERROR_PROMOTION_ACTIVE: DWORD = 8221; +pub const ERROR_NO_PROMOTION_ACTIVE: DWORD = 8222; +pub const ERROR_DS_OPERATIONS_ERROR: DWORD = 8224; +pub const ERROR_DS_PROTOCOL_ERROR: DWORD = 8225; +pub const ERROR_DS_TIMELIMIT_EXCEEDED: DWORD = 8226; +pub const ERROR_DS_SIZELIMIT_EXCEEDED: DWORD = 8227; +pub const ERROR_DS_ADMIN_LIMIT_EXCEEDED: DWORD = 8228; +pub const ERROR_DS_COMPARE_FALSE: DWORD = 8229; +pub const ERROR_DS_COMPARE_TRUE: DWORD = 8230; +pub const ERROR_DS_AUTH_METHOD_NOT_SUPPORTED: DWORD = 8231; +pub const ERROR_DS_STRONG_AUTH_REQUIRED: DWORD = 8232; +pub const ERROR_DS_INAPPROPRIATE_AUTH: DWORD = 8233; +pub const ERROR_DS_AUTH_UNKNOWN: DWORD = 8234; +pub const ERROR_DS_REFERRAL: DWORD = 8235; +pub const ERROR_DS_UNAVAILABLE_CRIT_EXTENSION: DWORD = 8236; +pub const ERROR_DS_CONFIDENTIALITY_REQUIRED: DWORD = 8237; +pub const ERROR_DS_INAPPROPRIATE_MATCHING: DWORD = 8238; +pub const ERROR_DS_CONSTRAINT_VIOLATION: DWORD = 8239; +pub const ERROR_DS_NO_SUCH_OBJECT: DWORD = 8240; +pub const ERROR_DS_ALIAS_PROBLEM: DWORD = 8241; +pub const ERROR_DS_INVALID_DN_SYNTAX: DWORD = 8242; +pub const ERROR_DS_IS_LEAF: DWORD = 8243; +pub const ERROR_DS_ALIAS_DEREF_PROBLEM: DWORD = 8244; +pub const ERROR_DS_UNWILLING_TO_PERFORM: DWORD = 8245; +pub const ERROR_DS_LOOP_DETECT: DWORD = 8246; +pub const ERROR_DS_NAMING_VIOLATION: DWORD = 8247; +pub const ERROR_DS_OBJECT_RESULTS_TOO_LARGE: DWORD = 8248; +pub const ERROR_DS_AFFECTS_MULTIPLE_DSAS: DWORD = 8249; +pub const ERROR_DS_SERVER_DOWN: DWORD = 8250; +pub const ERROR_DS_LOCAL_ERROR: DWORD = 8251; +pub const ERROR_DS_ENCODING_ERROR: DWORD = 8252; +pub const ERROR_DS_DECODING_ERROR: DWORD = 8253; +pub const ERROR_DS_FILTER_UNKNOWN: DWORD = 8254; +pub const ERROR_DS_PARAM_ERROR: DWORD = 8255; +pub const ERROR_DS_NOT_SUPPORTED: DWORD = 8256; +pub const ERROR_DS_NO_RESULTS_RETURNED: DWORD = 8257; +pub const ERROR_DS_CONTROL_NOT_FOUND: DWORD = 8258; +pub const ERROR_DS_CLIENT_LOOP: DWORD = 8259; +pub const ERROR_DS_REFERRAL_LIMIT_EXCEEDED: DWORD = 8260; +pub const ERROR_DS_SORT_CONTROL_MISSING: DWORD = 8261; +pub const ERROR_DS_OFFSET_RANGE_ERROR: DWORD = 8262; +pub const ERROR_DS_ROOT_MUST_BE_NC: DWORD = 8301; +pub const ERROR_DS_ADD_REPLICA_INHIBITED: DWORD = 8302; +pub const ERROR_DS_ATT_NOT_DEF_IN_SCHEMA: DWORD = 8303; +pub const ERROR_DS_MAX_OBJ_SIZE_EXCEEDED: DWORD = 8304; +pub const ERROR_DS_OBJ_STRING_NAME_EXISTS: DWORD = 8305; +pub const ERROR_DS_NO_RDN_DEFINED_IN_SCHEMA: DWORD = 8306; +pub const ERROR_DS_RDN_DOESNT_MATCH_SCHEMA: DWORD = 8307; +pub const ERROR_DS_NO_REQUESTED_ATTS_FOUND: DWORD = 8308; +pub const ERROR_DS_USER_BUFFER_TO_SMALL: DWORD = 8309; +pub const ERROR_DS_ATT_IS_NOT_ON_OBJ: DWORD = 8310; +pub const ERROR_DS_ILLEGAL_MOD_OPERATION: DWORD = 8311; +pub const ERROR_DS_OBJ_TOO_LARGE: DWORD = 8312; +pub const ERROR_DS_BAD_INSTANCE_TYPE: DWORD = 8313; +pub const ERROR_DS_MASTERDSA_REQUIRED: DWORD = 8314; +pub const ERROR_DS_OBJECT_CLASS_REQUIRED: DWORD = 8315; +pub const ERROR_DS_MISSING_REQUIRED_ATT: DWORD = 8316; +pub const ERROR_DS_ATT_NOT_DEF_FOR_CLASS: DWORD = 8317; +pub const ERROR_DS_ATT_ALREADY_EXISTS: DWORD = 8318; +pub const ERROR_DS_CANT_ADD_ATT_VALUES: DWORD = 8320; +pub const ERROR_DS_SINGLE_VALUE_CONSTRAINT: DWORD = 8321; +pub const ERROR_DS_RANGE_CONSTRAINT: DWORD = 8322; +pub const ERROR_DS_ATT_VAL_ALREADY_EXISTS: DWORD = 8323; +pub const ERROR_DS_CANT_REM_MISSING_ATT: DWORD = 8324; +pub const ERROR_DS_CANT_REM_MISSING_ATT_VAL: DWORD = 8325; +pub const ERROR_DS_ROOT_CANT_BE_SUBREF: DWORD = 8326; +pub const ERROR_DS_NO_CHAINING: DWORD = 8327; +pub const ERROR_DS_NO_CHAINED_EVAL: DWORD = 8328; +pub const ERROR_DS_NO_PARENT_OBJECT: DWORD = 8329; +pub const ERROR_DS_PARENT_IS_AN_ALIAS: DWORD = 8330; +pub const ERROR_DS_CANT_MIX_MASTER_AND_REPS: DWORD = 8331; +pub const ERROR_DS_CHILDREN_EXIST: DWORD = 8332; +pub const ERROR_DS_OBJ_NOT_FOUND: DWORD = 8333; +pub const ERROR_DS_ALIASED_OBJ_MISSING: DWORD = 8334; +pub const ERROR_DS_BAD_NAME_SYNTAX: DWORD = 8335; +pub const ERROR_DS_ALIAS_POINTS_TO_ALIAS: DWORD = 8336; +pub const ERROR_DS_CANT_DEREF_ALIAS: DWORD = 8337; +pub const ERROR_DS_OUT_OF_SCOPE: DWORD = 8338; +pub const ERROR_DS_OBJECT_BEING_REMOVED: DWORD = 8339; +pub const ERROR_DS_CANT_DELETE_DSA_OBJ: DWORD = 8340; +pub const ERROR_DS_GENERIC_ERROR: DWORD = 8341; +pub const ERROR_DS_DSA_MUST_BE_INT_MASTER: DWORD = 8342; +pub const ERROR_DS_CLASS_NOT_DSA: DWORD = 8343; +pub const ERROR_DS_INSUFF_ACCESS_RIGHTS: DWORD = 8344; +pub const ERROR_DS_ILLEGAL_SUPERIOR: DWORD = 8345; +pub const ERROR_DS_ATTRIBUTE_OWNED_BY_SAM: DWORD = 8346; +pub const ERROR_DS_NAME_TOO_MANY_PARTS: DWORD = 8347; +pub const ERROR_DS_NAME_TOO_LONG: DWORD = 8348; +pub const ERROR_DS_NAME_VALUE_TOO_LONG: DWORD = 8349; +pub const ERROR_DS_NAME_UNPARSEABLE: DWORD = 8350; +pub const ERROR_DS_NAME_TYPE_UNKNOWN: DWORD = 8351; +pub const ERROR_DS_NOT_AN_OBJECT: DWORD = 8352; +pub const ERROR_DS_SEC_DESC_TOO_SHORT: DWORD = 8353; +pub const ERROR_DS_SEC_DESC_INVALID: DWORD = 8354; +pub const ERROR_DS_NO_DELETED_NAME: DWORD = 8355; +pub const ERROR_DS_SUBREF_MUST_HAVE_PARENT: DWORD = 8356; +pub const ERROR_DS_NCNAME_MUST_BE_NC: DWORD = 8357; +pub const ERROR_DS_CANT_ADD_SYSTEM_ONLY: DWORD = 8358; +pub const ERROR_DS_CLASS_MUST_BE_CONCRETE: DWORD = 8359; +pub const ERROR_DS_INVALID_DMD: DWORD = 8360; +pub const ERROR_DS_OBJ_GUID_EXISTS: DWORD = 8361; +pub const ERROR_DS_NOT_ON_BACKLINK: DWORD = 8362; +pub const ERROR_DS_NO_CROSSREF_FOR_NC: DWORD = 8363; +pub const ERROR_DS_SHUTTING_DOWN: DWORD = 8364; +pub const ERROR_DS_UNKNOWN_OPERATION: DWORD = 8365; +pub const ERROR_DS_INVALID_ROLE_OWNER: DWORD = 8366; +pub const ERROR_DS_COULDNT_CONTACT_FSMO: DWORD = 8367; +pub const ERROR_DS_CROSS_NC_DN_RENAME: DWORD = 8368; +pub const ERROR_DS_CANT_MOD_SYSTEM_ONLY: DWORD = 8369; +pub const ERROR_DS_REPLICATOR_ONLY: DWORD = 8370; +pub const ERROR_DS_OBJ_CLASS_NOT_DEFINED: DWORD = 8371; +pub const ERROR_DS_OBJ_CLASS_NOT_SUBCLASS: DWORD = 8372; +pub const ERROR_DS_NAME_REFERENCE_INVALID: DWORD = 8373; +pub const ERROR_DS_CROSS_REF_EXISTS: DWORD = 8374; +pub const ERROR_DS_CANT_DEL_MASTER_CROSSREF: DWORD = 8375; +pub const ERROR_DS_SUBTREE_NOTIFY_NOT_NC_HEAD: DWORD = 8376; +pub const ERROR_DS_NOTIFY_FILTER_TOO_COMPLEX: DWORD = 8377; +pub const ERROR_DS_DUP_RDN: DWORD = 8378; +pub const ERROR_DS_DUP_OID: DWORD = 8379; +pub const ERROR_DS_DUP_MAPI_ID: DWORD = 8380; +pub const ERROR_DS_DUP_SCHEMA_ID_GUID: DWORD = 8381; +pub const ERROR_DS_DUP_LDAP_DISPLAY_NAME: DWORD = 8382; +pub const ERROR_DS_SEMANTIC_ATT_TEST: DWORD = 8383; +pub const ERROR_DS_SYNTAX_MISMATCH: DWORD = 8384; +pub const ERROR_DS_EXISTS_IN_MUST_HAVE: DWORD = 8385; +pub const ERROR_DS_EXISTS_IN_MAY_HAVE: DWORD = 8386; +pub const ERROR_DS_NONEXISTENT_MAY_HAVE: DWORD = 8387; +pub const ERROR_DS_NONEXISTENT_MUST_HAVE: DWORD = 8388; +pub const ERROR_DS_AUX_CLS_TEST_FAIL: DWORD = 8389; +pub const ERROR_DS_NONEXISTENT_POSS_SUP: DWORD = 8390; +pub const ERROR_DS_SUB_CLS_TEST_FAIL: DWORD = 8391; +pub const ERROR_DS_BAD_RDN_ATT_ID_SYNTAX: DWORD = 8392; +pub const ERROR_DS_EXISTS_IN_AUX_CLS: DWORD = 8393; +pub const ERROR_DS_EXISTS_IN_SUB_CLS: DWORD = 8394; +pub const ERROR_DS_EXISTS_IN_POSS_SUP: DWORD = 8395; +pub const ERROR_DS_RECALCSCHEMA_FAILED: DWORD = 8396; +pub const ERROR_DS_TREE_DELETE_NOT_FINISHED: DWORD = 8397; +pub const ERROR_DS_CANT_DELETE: DWORD = 8398; +pub const ERROR_DS_ATT_SCHEMA_REQ_ID: DWORD = 8399; +pub const ERROR_DS_BAD_ATT_SCHEMA_SYNTAX: DWORD = 8400; +pub const ERROR_DS_CANT_CACHE_ATT: DWORD = 8401; +pub const ERROR_DS_CANT_CACHE_CLASS: DWORD = 8402; +pub const ERROR_DS_CANT_REMOVE_ATT_CACHE: DWORD = 8403; +pub const ERROR_DS_CANT_REMOVE_CLASS_CACHE: DWORD = 8404; +pub const ERROR_DS_CANT_RETRIEVE_DN: DWORD = 8405; +pub const ERROR_DS_MISSING_SUPREF: DWORD = 8406; +pub const ERROR_DS_CANT_RETRIEVE_INSTANCE: DWORD = 8407; +pub const ERROR_DS_CODE_INCONSISTENCY: DWORD = 8408; +pub const ERROR_DS_DATABASE_ERROR: DWORD = 8409; +pub const ERROR_DS_GOVERNSID_MISSING: DWORD = 8410; +pub const ERROR_DS_MISSING_EXPECTED_ATT: DWORD = 8411; +pub const ERROR_DS_NCNAME_MISSING_CR_REF: DWORD = 8412; +pub const ERROR_DS_SECURITY_CHECKING_ERROR: DWORD = 8413; +pub const ERROR_DS_SCHEMA_NOT_LOADED: DWORD = 8414; +pub const ERROR_DS_SCHEMA_ALLOC_FAILED: DWORD = 8415; +pub const ERROR_DS_ATT_SCHEMA_REQ_SYNTAX: DWORD = 8416; +pub const ERROR_DS_GCVERIFY_ERROR: DWORD = 8417; +pub const ERROR_DS_DRA_SCHEMA_MISMATCH: DWORD = 8418; +pub const ERROR_DS_CANT_FIND_DSA_OBJ: DWORD = 8419; +pub const ERROR_DS_CANT_FIND_EXPECTED_NC: DWORD = 8420; +pub const ERROR_DS_CANT_FIND_NC_IN_CACHE: DWORD = 8421; +pub const ERROR_DS_CANT_RETRIEVE_CHILD: DWORD = 8422; +pub const ERROR_DS_SECURITY_ILLEGAL_MODIFY: DWORD = 8423; +pub const ERROR_DS_CANT_REPLACE_HIDDEN_REC: DWORD = 8424; +pub const ERROR_DS_BAD_HIERARCHY_FILE: DWORD = 8425; +pub const ERROR_DS_BUILD_HIERARCHY_TABLE_FAILED: DWORD = 8426; +pub const ERROR_DS_CONFIG_PARAM_MISSING: DWORD = 8427; +pub const ERROR_DS_COUNTING_AB_INDICES_FAILED: DWORD = 8428; +pub const ERROR_DS_HIERARCHY_TABLE_MALLOC_FAILED: DWORD = 8429; +pub const ERROR_DS_INTERNAL_FAILURE: DWORD = 8430; +pub const ERROR_DS_UNKNOWN_ERROR: DWORD = 8431; +pub const ERROR_DS_ROOT_REQUIRES_CLASS_TOP: DWORD = 8432; +pub const ERROR_DS_REFUSING_FSMO_ROLES: DWORD = 8433; +pub const ERROR_DS_MISSING_FSMO_SETTINGS: DWORD = 8434; +pub const ERROR_DS_UNABLE_TO_SURRENDER_ROLES: DWORD = 8435; +pub const ERROR_DS_DRA_GENERIC: DWORD = 8436; +pub const ERROR_DS_DRA_INVALID_PARAMETER: DWORD = 8437; +pub const ERROR_DS_DRA_BUSY: DWORD = 8438; +pub const ERROR_DS_DRA_BAD_DN: DWORD = 8439; +pub const ERROR_DS_DRA_BAD_NC: DWORD = 8440; +pub const ERROR_DS_DRA_DN_EXISTS: DWORD = 8441; +pub const ERROR_DS_DRA_INTERNAL_ERROR: DWORD = 8442; +pub const ERROR_DS_DRA_INCONSISTENT_DIT: DWORD = 8443; +pub const ERROR_DS_DRA_CONNECTION_FAILED: DWORD = 8444; +pub const ERROR_DS_DRA_BAD_INSTANCE_TYPE: DWORD = 8445; +pub const ERROR_DS_DRA_OUT_OF_MEM: DWORD = 8446; +pub const ERROR_DS_DRA_MAIL_PROBLEM: DWORD = 8447; +pub const ERROR_DS_DRA_REF_ALREADY_EXISTS: DWORD = 8448; +pub const ERROR_DS_DRA_REF_NOT_FOUND: DWORD = 8449; +pub const ERROR_DS_DRA_OBJ_IS_REP_SOURCE: DWORD = 8450; +pub const ERROR_DS_DRA_DB_ERROR: DWORD = 8451; +pub const ERROR_DS_DRA_NO_REPLICA: DWORD = 8452; +pub const ERROR_DS_DRA_ACCESS_DENIED: DWORD = 8453; +pub const ERROR_DS_DRA_NOT_SUPPORTED: DWORD = 8454; +pub const ERROR_DS_DRA_RPC_CANCELLED: DWORD = 8455; +pub const ERROR_DS_DRA_SOURCE_DISABLED: DWORD = 8456; +pub const ERROR_DS_DRA_SINK_DISABLED: DWORD = 8457; +pub const ERROR_DS_DRA_NAME_COLLISION: DWORD = 8458; +pub const ERROR_DS_DRA_SOURCE_REINSTALLED: DWORD = 8459; +pub const ERROR_DS_DRA_MISSING_PARENT: DWORD = 8460; +pub const ERROR_DS_DRA_PREEMPTED: DWORD = 8461; +pub const ERROR_DS_DRA_ABANDON_SYNC: DWORD = 8462; +pub const ERROR_DS_DRA_SHUTDOWN: DWORD = 8463; +pub const ERROR_DS_DRA_INCOMPATIBLE_PARTIAL_SET: DWORD = 8464; +pub const ERROR_DS_DRA_SOURCE_IS_PARTIAL_REPLICA: DWORD = 8465; +pub const ERROR_DS_DRA_EXTN_CONNECTION_FAILED: DWORD = 8466; +pub const ERROR_DS_INSTALL_SCHEMA_MISMATCH: DWORD = 8467; +pub const ERROR_DS_DUP_LINK_ID: DWORD = 8468; +pub const ERROR_DS_NAME_ERROR_RESOLVING: DWORD = 8469; +pub const ERROR_DS_NAME_ERROR_NOT_FOUND: DWORD = 8470; +pub const ERROR_DS_NAME_ERROR_NOT_UNIQUE: DWORD = 8471; +pub const ERROR_DS_NAME_ERROR_NO_MAPPING: DWORD = 8472; +pub const ERROR_DS_NAME_ERROR_DOMAIN_ONLY: DWORD = 8473; +pub const ERROR_DS_NAME_ERROR_NO_SYNTACTICAL_MAPPING: DWORD = 8474; +pub const ERROR_DS_CONSTRUCTED_ATT_MOD: DWORD = 8475; +pub const ERROR_DS_WRONG_OM_OBJ_CLASS: DWORD = 8476; +pub const ERROR_DS_DRA_REPL_PENDING: DWORD = 8477; +pub const ERROR_DS_DS_REQUIRED: DWORD = 8478; +pub const ERROR_DS_INVALID_LDAP_DISPLAY_NAME: DWORD = 8479; +pub const ERROR_DS_NON_BASE_SEARCH: DWORD = 8480; +pub const ERROR_DS_CANT_RETRIEVE_ATTS: DWORD = 8481; +pub const ERROR_DS_BACKLINK_WITHOUT_LINK: DWORD = 8482; +pub const ERROR_DS_EPOCH_MISMATCH: DWORD = 8483; +pub const ERROR_DS_SRC_NAME_MISMATCH: DWORD = 8484; +pub const ERROR_DS_SRC_AND_DST_NC_IDENTICAL: DWORD = 8485; +pub const ERROR_DS_DST_NC_MISMATCH: DWORD = 8486; +pub const ERROR_DS_NOT_AUTHORITIVE_FOR_DST_NC: DWORD = 8487; +pub const ERROR_DS_SRC_GUID_MISMATCH: DWORD = 8488; +pub const ERROR_DS_CANT_MOVE_DELETED_OBJECT: DWORD = 8489; +pub const ERROR_DS_PDC_OPERATION_IN_PROGRESS: DWORD = 8490; +pub const ERROR_DS_CROSS_DOMAIN_CLEANUP_REQD: DWORD = 8491; +pub const ERROR_DS_ILLEGAL_XDOM_MOVE_OPERATION: DWORD = 8492; +pub const ERROR_DS_CANT_WITH_ACCT_GROUP_MEMBERSHPS: DWORD = 8493; +pub const ERROR_DS_NC_MUST_HAVE_NC_PARENT: DWORD = 8494; +pub const ERROR_DS_CR_IMPOSSIBLE_TO_VALIDATE: DWORD = 8495; +pub const ERROR_DS_DST_DOMAIN_NOT_NATIVE: DWORD = 8496; +pub const ERROR_DS_MISSING_INFRASTRUCTURE_CONTAINER: DWORD = 8497; +pub const ERROR_DS_CANT_MOVE_ACCOUNT_GROUP: DWORD = 8498; +pub const ERROR_DS_CANT_MOVE_RESOURCE_GROUP: DWORD = 8499; +pub const ERROR_DS_INVALID_SEARCH_FLAG: DWORD = 8500; +pub const ERROR_DS_NO_TREE_DELETE_ABOVE_NC: DWORD = 8501; +pub const ERROR_DS_COULDNT_LOCK_TREE_FOR_DELETE: DWORD = 8502; +pub const ERROR_DS_COULDNT_IDENTIFY_OBJECTS_FOR_TREE_DELETE: DWORD = 8503; +pub const ERROR_DS_SAM_INIT_FAILURE: DWORD = 8504; +pub const ERROR_DS_SENSITIVE_GROUP_VIOLATION: DWORD = 8505; +pub const ERROR_DS_CANT_MOD_PRIMARYGROUPID: DWORD = 8506; +pub const ERROR_DS_ILLEGAL_BASE_SCHEMA_MOD: DWORD = 8507; +pub const ERROR_DS_NONSAFE_SCHEMA_CHANGE: DWORD = 8508; +pub const ERROR_DS_SCHEMA_UPDATE_DISALLOWED: DWORD = 8509; +pub const ERROR_DS_CANT_CREATE_UNDER_SCHEMA: DWORD = 8510; +pub const ERROR_DS_INSTALL_NO_SRC_SCH_VERSION: DWORD = 8511; +pub const ERROR_DS_INSTALL_NO_SCH_VERSION_IN_INIFILE: DWORD = 8512; +pub const ERROR_DS_INVALID_GROUP_TYPE: DWORD = 8513; +pub const ERROR_DS_NO_NEST_GLOBALGROUP_IN_MIXEDDOMAIN: DWORD = 8514; +pub const ERROR_DS_NO_NEST_LOCALGROUP_IN_MIXEDDOMAIN: DWORD = 8515; +pub const ERROR_DS_GLOBAL_CANT_HAVE_LOCAL_MEMBER: DWORD = 8516; +pub const ERROR_DS_GLOBAL_CANT_HAVE_UNIVERSAL_MEMBER: DWORD = 8517; +pub const ERROR_DS_UNIVERSAL_CANT_HAVE_LOCAL_MEMBER: DWORD = 8518; +pub const ERROR_DS_GLOBAL_CANT_HAVE_CROSSDOMAIN_MEMBER: DWORD = 8519; +pub const ERROR_DS_LOCAL_CANT_HAVE_CROSSDOMAIN_LOCAL_MEMBER: DWORD = 8520; +pub const ERROR_DS_HAVE_PRIMARY_MEMBERS: DWORD = 8521; +pub const ERROR_DS_STRING_SD_CONVERSION_FAILED: DWORD = 8522; +pub const ERROR_DS_NAMING_MASTER_GC: DWORD = 8523; +pub const ERROR_DS_DNS_LOOKUP_FAILURE: DWORD = 8524; +pub const ERROR_DS_COULDNT_UPDATE_SPNS: DWORD = 8525; +pub const ERROR_DS_CANT_RETRIEVE_SD: DWORD = 8526; +pub const ERROR_DS_KEY_NOT_UNIQUE: DWORD = 8527; +pub const ERROR_DS_WRONG_LINKED_ATT_SYNTAX: DWORD = 8528; +pub const ERROR_DS_SAM_NEED_BOOTKEY_PASSWORD: DWORD = 8529; +pub const ERROR_DS_SAM_NEED_BOOTKEY_FLOPPY: DWORD = 8530; +pub const ERROR_DS_CANT_START: DWORD = 8531; +pub const ERROR_DS_INIT_FAILURE: DWORD = 8532; +pub const ERROR_DS_NO_PKT_PRIVACY_ON_CONNECTION: DWORD = 8533; +pub const ERROR_DS_SOURCE_DOMAIN_IN_FOREST: DWORD = 8534; +pub const ERROR_DS_DESTINATION_DOMAIN_NOT_IN_FOREST: DWORD = 8535; +pub const ERROR_DS_DESTINATION_AUDITING_NOT_ENABLED: DWORD = 8536; +pub const ERROR_DS_CANT_FIND_DC_FOR_SRC_DOMAIN: DWORD = 8537; +pub const ERROR_DS_SRC_OBJ_NOT_GROUP_OR_USER: DWORD = 8538; +pub const ERROR_DS_SRC_SID_EXISTS_IN_FOREST: DWORD = 8539; +pub const ERROR_DS_SRC_AND_DST_OBJECT_CLASS_MISMATCH: DWORD = 8540; +pub const ERROR_SAM_INIT_FAILURE: DWORD = 8541; +pub const ERROR_DS_DRA_SCHEMA_INFO_SHIP: DWORD = 8542; +pub const ERROR_DS_DRA_SCHEMA_CONFLICT: DWORD = 8543; +pub const ERROR_DS_DRA_EARLIER_SCHEMA_CONFLICT: DWORD = 8544; +pub const ERROR_DS_DRA_OBJ_NC_MISMATCH: DWORD = 8545; +pub const ERROR_DS_NC_STILL_HAS_DSAS: DWORD = 8546; +pub const ERROR_DS_GC_REQUIRED: DWORD = 8547; +pub const ERROR_DS_LOCAL_MEMBER_OF_LOCAL_ONLY: DWORD = 8548; +pub const ERROR_DS_NO_FPO_IN_UNIVERSAL_GROUPS: DWORD = 8549; +pub const ERROR_DS_CANT_ADD_TO_GC: DWORD = 8550; +pub const ERROR_DS_NO_CHECKPOINT_WITH_PDC: DWORD = 8551; +pub const ERROR_DS_SOURCE_AUDITING_NOT_ENABLED: DWORD = 8552; +pub const ERROR_DS_CANT_CREATE_IN_NONDOMAIN_NC: DWORD = 8553; +pub const ERROR_DS_INVALID_NAME_FOR_SPN: DWORD = 8554; +pub const ERROR_DS_FILTER_USES_CONTRUCTED_ATTRS: DWORD = 8555; +pub const ERROR_DS_UNICODEPWD_NOT_IN_QUOTES: DWORD = 8556; +pub const ERROR_DS_MACHINE_ACCOUNT_QUOTA_EXCEEDED: DWORD = 8557; +pub const ERROR_DS_MUST_BE_RUN_ON_DST_DC: DWORD = 8558; +pub const ERROR_DS_SRC_DC_MUST_BE_SP4_OR_GREATER: DWORD = 8559; +pub const ERROR_DS_CANT_TREE_DELETE_CRITICAL_OBJ: DWORD = 8560; +pub const ERROR_DS_INIT_FAILURE_CONSOLE: DWORD = 8561; +pub const ERROR_DS_SAM_INIT_FAILURE_CONSOLE: DWORD = 8562; +pub const ERROR_DS_FOREST_VERSION_TOO_HIGH: DWORD = 8563; +pub const ERROR_DS_DOMAIN_VERSION_TOO_HIGH: DWORD = 8564; +pub const ERROR_DS_FOREST_VERSION_TOO_LOW: DWORD = 8565; +pub const ERROR_DS_DOMAIN_VERSION_TOO_LOW: DWORD = 8566; +pub const ERROR_DS_INCOMPATIBLE_VERSION: DWORD = 8567; +pub const ERROR_DS_LOW_DSA_VERSION: DWORD = 8568; +pub const ERROR_DS_NO_BEHAVIOR_VERSION_IN_MIXEDDOMAIN: DWORD = 8569; +pub const ERROR_DS_NOT_SUPPORTED_SORT_ORDER: DWORD = 8570; +pub const ERROR_DS_NAME_NOT_UNIQUE: DWORD = 8571; +pub const ERROR_DS_MACHINE_ACCOUNT_CREATED_PRENT4: DWORD = 8572; +pub const ERROR_DS_OUT_OF_VERSION_STORE: DWORD = 8573; +pub const ERROR_DS_INCOMPATIBLE_CONTROLS_USED: DWORD = 8574; +pub const ERROR_DS_NO_REF_DOMAIN: DWORD = 8575; +pub const ERROR_DS_RESERVED_LINK_ID: DWORD = 8576; +pub const ERROR_DS_LINK_ID_NOT_AVAILABLE: DWORD = 8577; +pub const ERROR_DS_AG_CANT_HAVE_UNIVERSAL_MEMBER: DWORD = 8578; +pub const ERROR_DS_MODIFYDN_DISALLOWED_BY_INSTANCE_TYPE: DWORD = 8579; +pub const ERROR_DS_NO_OBJECT_MOVE_IN_SCHEMA_NC: DWORD = 8580; +pub const ERROR_DS_MODIFYDN_DISALLOWED_BY_FLAG: DWORD = 8581; +pub const ERROR_DS_MODIFYDN_WRONG_GRANDPARENT: DWORD = 8582; +pub const ERROR_DS_NAME_ERROR_TRUST_REFERRAL: DWORD = 8583; +pub const ERROR_NOT_SUPPORTED_ON_STANDARD_SERVER: DWORD = 8584; +pub const ERROR_DS_CANT_ACCESS_REMOTE_PART_OF_AD: DWORD = 8585; +pub const ERROR_DS_CR_IMPOSSIBLE_TO_VALIDATE_V2: DWORD = 8586; +pub const ERROR_DS_THREAD_LIMIT_EXCEEDED: DWORD = 8587; +pub const ERROR_DS_NOT_CLOSEST: DWORD = 8588; +pub const ERROR_DS_CANT_DERIVE_SPN_WITHOUT_SERVER_REF: DWORD = 8589; +pub const ERROR_DS_SINGLE_USER_MODE_FAILED: DWORD = 8590; +pub const ERROR_DS_NTDSCRIPT_SYNTAX_ERROR: DWORD = 8591; +pub const ERROR_DS_NTDSCRIPT_PROCESS_ERROR: DWORD = 8592; +pub const ERROR_DS_DIFFERENT_REPL_EPOCHS: DWORD = 8593; +pub const ERROR_DS_DRS_EXTENSIONS_CHANGED: DWORD = 8594; +pub const ERROR_DS_REPLICA_SET_CHANGE_NOT_ALLOWED_ON_DISABLED_CR: DWORD = 8595; +pub const ERROR_DS_NO_MSDS_INTID: DWORD = 8596; +pub const ERROR_DS_DUP_MSDS_INTID: DWORD = 8597; +pub const ERROR_DS_EXISTS_IN_RDNATTID: DWORD = 8598; +pub const ERROR_DS_AUTHORIZATION_FAILED: DWORD = 8599; +pub const ERROR_DS_INVALID_SCRIPT: DWORD = 8600; +pub const ERROR_DS_REMOTE_CROSSREF_OP_FAILED: DWORD = 8601; +pub const ERROR_DS_CROSS_REF_BUSY: DWORD = 8602; +pub const ERROR_DS_CANT_DERIVE_SPN_FOR_DELETED_DOMAIN: DWORD = 8603; +pub const ERROR_DS_CANT_DEMOTE_WITH_WRITEABLE_NC: DWORD = 8604; +pub const ERROR_DS_DUPLICATE_ID_FOUND: DWORD = 8605; +pub const ERROR_DS_INSUFFICIENT_ATTR_TO_CREATE_OBJECT: DWORD = 8606; +pub const ERROR_DS_GROUP_CONVERSION_ERROR: DWORD = 8607; +pub const ERROR_DS_CANT_MOVE_APP_BASIC_GROUP: DWORD = 8608; +pub const ERROR_DS_CANT_MOVE_APP_QUERY_GROUP: DWORD = 8609; +pub const ERROR_DS_ROLE_NOT_VERIFIED: DWORD = 8610; +pub const ERROR_DS_WKO_CONTAINER_CANNOT_BE_SPECIAL: DWORD = 8611; +pub const ERROR_DS_DOMAIN_RENAME_IN_PROGRESS: DWORD = 8612; +pub const ERROR_DS_EXISTING_AD_CHILD_NC: DWORD = 8613; +pub const ERROR_DS_REPL_LIFETIME_EXCEEDED: DWORD = 8614; +pub const ERROR_DS_DISALLOWED_IN_SYSTEM_CONTAINER: DWORD = 8615; +pub const ERROR_DS_LDAP_SEND_QUEUE_FULL: DWORD = 8616; +pub const ERROR_DS_DRA_OUT_SCHEDULE_WINDOW: DWORD = 8617; +pub const ERROR_SXS_SECTION_NOT_FOUND: DWORD = 14000; +pub const ERROR_SXS_CANT_GEN_ACTCTX: DWORD = 14001; +pub const ERROR_SXS_INVALID_ACTCTXDATA_FORMAT: DWORD = 14002; +pub const ERROR_SXS_ASSEMBLY_NOT_FOUND: DWORD = 14003; +pub const ERROR_SXS_MANIFEST_FORMAT_ERROR: DWORD = 14004; +pub const ERROR_SXS_MANIFEST_PARSE_ERROR: DWORD = 14005; +pub const ERROR_SXS_ACTIVATION_CONTEXT_DISABLED: DWORD = 14006; +pub const ERROR_SXS_KEY_NOT_FOUND: DWORD = 14007; +pub const ERROR_SXS_VERSION_CONFLICT: DWORD = 14008; +pub const ERROR_SXS_WRONG_SECTION_TYPE: DWORD = 14009; +pub const ERROR_SXS_THREAD_QUERIES_DISABLED: DWORD = 14010; +pub const ERROR_SXS_PROCESS_DEFAULT_ALREADY_SET: DWORD = 14011; +pub const ERROR_SXS_UNKNOWN_ENCODING_GROUP: DWORD = 14012; +pub const ERROR_SXS_UNKNOWN_ENCODING: DWORD = 14013; +pub const ERROR_SXS_INVALID_XML_NAMESPACE_URI: DWORD = 14014; +pub const ERROR_SXS_ROOT_MANIFEST_DEPENDENCY_NOT_INSTALLED: DWORD = 14015; +pub const ERROR_SXS_LEAF_MANIFEST_DEPENDENCY_NOT_INSTALLED: DWORD = 14016; +pub const ERROR_SXS_INVALID_ASSEMBLY_IDENTITY_ATTRIBUTE: DWORD = 14017; +pub const ERROR_SXS_MANIFEST_MISSING_REQUIRED_DEFAULT_NAMESPACE: DWORD = 14018; +pub const ERROR_SXS_MANIFEST_INVALID_REQUIRED_DEFAULT_NAMESPACE: DWORD = 14019; +pub const ERROR_SXS_PRIVATE_MANIFEST_CROSS_PATH_WITH_REPARSE_POINT: DWORD = 14020; +pub const ERROR_SXS_DUPLICATE_DLL_NAME: DWORD = 14021; +pub const ERROR_SXS_DUPLICATE_WINDOWCLASS_NAME: DWORD = 14022; +pub const ERROR_SXS_DUPLICATE_CLSID: DWORD = 14023; +pub const ERROR_SXS_DUPLICATE_IID: DWORD = 14024; +pub const ERROR_SXS_DUPLICATE_TLBID: DWORD = 14025; +pub const ERROR_SXS_DUPLICATE_PROGID: DWORD = 14026; +pub const ERROR_SXS_DUPLICATE_ASSEMBLY_NAME: DWORD = 14027; +pub const ERROR_SXS_FILE_HASH_MISMATCH: DWORD = 14028; +pub const ERROR_SXS_POLICY_PARSE_ERROR: DWORD = 14029; +pub const ERROR_SXS_XML_E_MISSINGQUOTE: DWORD = 14030; +pub const ERROR_SXS_XML_E_COMMENTSYNTAX: DWORD = 14031; +pub const ERROR_SXS_XML_E_BADSTARTNAMECHAR: DWORD = 14032; +pub const ERROR_SXS_XML_E_BADNAMECHAR: DWORD = 14033; +pub const ERROR_SXS_XML_E_BADCHARINSTRING: DWORD = 14034; +pub const ERROR_SXS_XML_E_XMLDECLSYNTAX: DWORD = 14035; +pub const ERROR_SXS_XML_E_BADCHARDATA: DWORD = 14036; +pub const ERROR_SXS_XML_E_MISSINGWHITESPACE: DWORD = 14037; +pub const ERROR_SXS_XML_E_EXPECTINGTAGEND: DWORD = 14038; +pub const ERROR_SXS_XML_E_MISSINGSEMICOLON: DWORD = 14039; +pub const ERROR_SXS_XML_E_UNBALANCEDPAREN: DWORD = 14040; +pub const ERROR_SXS_XML_E_INTERNALERROR: DWORD = 14041; +pub const ERROR_SXS_XML_E_UNEXPECTED_WHITESPACE: DWORD = 14042; +pub const ERROR_SXS_XML_E_INCOMPLETE_ENCODING: DWORD = 14043; +pub const ERROR_SXS_XML_E_MISSING_PAREN: DWORD = 14044; +pub const ERROR_SXS_XML_E_EXPECTINGCLOSEQUOTE: DWORD = 14045; +pub const ERROR_SXS_XML_E_MULTIPLE_COLONS: DWORD = 14046; +pub const ERROR_SXS_XML_E_INVALID_DECIMAL: DWORD = 14047; +pub const ERROR_SXS_XML_E_INVALID_HEXIDECIMAL: DWORD = 14048; +pub const ERROR_SXS_XML_E_INVALID_UNICODE: DWORD = 14049; +pub const ERROR_SXS_XML_E_WHITESPACEORQUESTIONMARK: DWORD = 14050; +pub const ERROR_SXS_XML_E_UNEXPECTEDENDTAG: DWORD = 14051; +pub const ERROR_SXS_XML_E_UNCLOSEDTAG: DWORD = 14052; +pub const ERROR_SXS_XML_E_DUPLICATEATTRIBUTE: DWORD = 14053; +pub const ERROR_SXS_XML_E_MULTIPLEROOTS: DWORD = 14054; +pub const ERROR_SXS_XML_E_INVALIDATROOTLEVEL: DWORD = 14055; +pub const ERROR_SXS_XML_E_BADXMLDECL: DWORD = 14056; +pub const ERROR_SXS_XML_E_MISSINGROOT: DWORD = 14057; +pub const ERROR_SXS_XML_E_UNEXPECTEDEOF: DWORD = 14058; +pub const ERROR_SXS_XML_E_BADPEREFINSUBSET: DWORD = 14059; +pub const ERROR_SXS_XML_E_UNCLOSEDSTARTTAG: DWORD = 14060; +pub const ERROR_SXS_XML_E_UNCLOSEDENDTAG: DWORD = 14061; +pub const ERROR_SXS_XML_E_UNCLOSEDSTRING: DWORD = 14062; +pub const ERROR_SXS_XML_E_UNCLOSEDCOMMENT: DWORD = 14063; +pub const ERROR_SXS_XML_E_UNCLOSEDDECL: DWORD = 14064; +pub const ERROR_SXS_XML_E_UNCLOSEDCDATA: DWORD = 14065; +pub const ERROR_SXS_XML_E_RESERVEDNAMESPACE: DWORD = 14066; +pub const ERROR_SXS_XML_E_INVALIDENCODING: DWORD = 14067; +pub const ERROR_SXS_XML_E_INVALIDSWITCH: DWORD = 14068; +pub const ERROR_SXS_XML_E_BADXMLCASE: DWORD = 14069; +pub const ERROR_SXS_XML_E_INVALID_STANDALONE: DWORD = 14070; +pub const ERROR_SXS_XML_E_UNEXPECTED_STANDALONE: DWORD = 14071; +pub const ERROR_SXS_XML_E_INVALID_VERSION: DWORD = 14072; +pub const ERROR_SXS_XML_E_MISSINGEQUALS: DWORD = 14073; +pub const ERROR_SXS_PROTECTION_RECOVERY_FAILED: DWORD = 14074; +pub const ERROR_SXS_PROTECTION_PUBLIC_KEY_TOO_SHORT: DWORD = 14075; +pub const ERROR_SXS_PROTECTION_CATALOG_NOT_VALID: DWORD = 14076; +pub const ERROR_SXS_UNTRANSLATABLE_HRESULT: DWORD = 14077; +pub const ERROR_SXS_PROTECTION_CATALOG_FILE_MISSING: DWORD = 14078; +pub const ERROR_SXS_MISSING_ASSEMBLY_IDENTITY_ATTRIBUTE: DWORD = 14079; +pub const ERROR_SXS_INVALID_ASSEMBLY_IDENTITY_ATTRIBUTE_NAME: DWORD = 14080; +pub const ERROR_SXS_ASSEMBLY_MISSING: DWORD = 14081; +pub const ERROR_SXS_CORRUPT_ACTIVATION_STACK: DWORD = 14082; +pub const ERROR_SXS_CORRUPTION: DWORD = 14083; +pub const ERROR_SXS_EARLY_DEACTIVATION: DWORD = 14084; +pub const ERROR_SXS_INVALID_DEACTIVATION: DWORD = 14085; +pub const ERROR_SXS_MULTIPLE_DEACTIVATION: DWORD = 14086; +pub const ERROR_SXS_PROCESS_TERMINATION_REQUESTED: DWORD = 14087; +pub const ERROR_SXS_RELEASE_ACTIVATION_CONTEXT: DWORD = 14088; +pub const ERROR_SXS_SYSTEM_DEFAULT_ACTIVATION_CONTEXT_EMPTY: DWORD = 14089; +pub const ERROR_SXS_INVALID_IDENTITY_ATTRIBUTE_VALUE: DWORD = 14090; +pub const ERROR_SXS_INVALID_IDENTITY_ATTRIBUTE_NAME: DWORD = 14091; +pub const ERROR_SXS_IDENTITY_DUPLICATE_ATTRIBUTE: DWORD = 14092; +pub const ERROR_SXS_IDENTITY_PARSE_ERROR: DWORD = 14093; +pub const ERROR_MALFORMED_SUBSTITUTION_STRING: DWORD = 14094; +pub const ERROR_SXS_INCORRECT_PUBLIC_KEY_TOKEN: DWORD = 14095; +pub const ERROR_UNMAPPED_SUBSTITUTION_STRING: DWORD = 14096; +pub const ERROR_SXS_ASSEMBLY_NOT_LOCKED: DWORD = 14097; +pub const ERROR_SXS_COMPONENT_STORE_CORRUPT: DWORD = 14098; +pub const ERROR_ADVANCED_INSTALLER_FAILED: DWORD = 14099; +pub const ERROR_XML_ENCODING_MISMATCH: DWORD = 14100; +pub const ERROR_SXS_MANIFEST_IDENTITY_SAME_BUT_CONTENTS_DIFFERENT: DWORD = 14101; +pub const ERROR_SXS_IDENTITIES_DIFFERENT: DWORD = 14102; +pub const ERROR_SXS_ASSEMBLY_IS_NOT_A_DEPLOYMENT: DWORD = 14103; +pub const ERROR_SXS_FILE_NOT_PART_OF_ASSEMBLY: DWORD = 14104; +pub const ERROR_SXS_MANIFEST_TOO_BIG: DWORD = 14105; +pub const ERROR_SXS_SETTING_NOT_REGISTERED: DWORD = 14106; +pub const ERROR_SXS_TRANSACTION_CLOSURE_INCOMPLETE: DWORD = 14107; +pub const ERROR_SMI_PRIMITIVE_INSTALLER_FAILED: DWORD = 14108; +pub const ERROR_GENERIC_COMMAND_FAILED: DWORD = 14109; +pub const ERROR_SXS_FILE_HASH_MISSING: DWORD = 14110; +pub const ERROR_IPSEC_QM_POLICY_EXISTS: DWORD = 13000; +pub const ERROR_IPSEC_QM_POLICY_NOT_FOUND: DWORD = 13001; +pub const ERROR_IPSEC_QM_POLICY_IN_USE: DWORD = 13002; +pub const ERROR_IPSEC_MM_POLICY_EXISTS: DWORD = 13003; +pub const ERROR_IPSEC_MM_POLICY_NOT_FOUND: DWORD = 13004; +pub const ERROR_IPSEC_MM_POLICY_IN_USE: DWORD = 13005; +pub const ERROR_IPSEC_MM_FILTER_EXISTS: DWORD = 13006; +pub const ERROR_IPSEC_MM_FILTER_NOT_FOUND: DWORD = 13007; +pub const ERROR_IPSEC_TRANSPORT_FILTER_EXISTS: DWORD = 13008; +pub const ERROR_IPSEC_TRANSPORT_FILTER_NOT_FOUND: DWORD = 13009; +pub const ERROR_IPSEC_MM_AUTH_EXISTS: DWORD = 13010; +pub const ERROR_IPSEC_MM_AUTH_NOT_FOUND: DWORD = 13011; +pub const ERROR_IPSEC_MM_AUTH_IN_USE: DWORD = 13012; +pub const ERROR_IPSEC_DEFAULT_MM_POLICY_NOT_FOUND: DWORD = 13013; +pub const ERROR_IPSEC_DEFAULT_MM_AUTH_NOT_FOUND: DWORD = 13014; +pub const ERROR_IPSEC_DEFAULT_QM_POLICY_NOT_FOUND: DWORD = 13015; +pub const ERROR_IPSEC_TUNNEL_FILTER_EXISTS: DWORD = 13016; +pub const ERROR_IPSEC_TUNNEL_FILTER_NOT_FOUND: DWORD = 13017; +pub const ERROR_IPSEC_MM_FILTER_PENDING_DELETION: DWORD = 13018; +pub const ERROR_IPSEC_TRANSPORT_FILTER_PENDING_DELETION: DWORD = 13019; +pub const ERROR_IPSEC_TUNNEL_FILTER_PENDING_DELETION: DWORD = 13020; +pub const ERROR_IPSEC_MM_POLICY_PENDING_DELETION: DWORD = 13021; +pub const ERROR_IPSEC_MM_AUTH_PENDING_DELETION: DWORD = 13022; +pub const ERROR_IPSEC_QM_POLICY_PENDING_DELETION: DWORD = 13023; +pub const ERROR_IPSEC_IKE_NEG_STATUS_BEGIN: DWORD = 13800; +pub const ERROR_IPSEC_IKE_AUTH_FAIL: DWORD = 13801; +pub const ERROR_IPSEC_IKE_ATTRIB_FAIL: DWORD = 13802; +pub const ERROR_IPSEC_IKE_NEGOTIATION_PENDING: DWORD = 13803; +pub const ERROR_IPSEC_IKE_GENERAL_PROCESSING_ERROR: DWORD = 13804; +pub const ERROR_IPSEC_IKE_TIMED_OUT: DWORD = 13805; +pub const ERROR_IPSEC_IKE_NO_CERT: DWORD = 13806; +pub const ERROR_IPSEC_IKE_SA_DELETED: DWORD = 13807; +pub const ERROR_IPSEC_IKE_SA_REAPED: DWORD = 13808; +pub const ERROR_IPSEC_IKE_MM_ACQUIRE_DROP: DWORD = 13809; +pub const ERROR_IPSEC_IKE_QM_ACQUIRE_DROP: DWORD = 13810; +pub const ERROR_IPSEC_IKE_QUEUE_DROP_MM: DWORD = 13811; +pub const ERROR_IPSEC_IKE_QUEUE_DROP_NO_MM: DWORD = 13812; +pub const ERROR_IPSEC_IKE_DROP_NO_RESPONSE: DWORD = 13813; +pub const ERROR_IPSEC_IKE_MM_DELAY_DROP: DWORD = 13814; +pub const ERROR_IPSEC_IKE_QM_DELAY_DROP: DWORD = 13815; +pub const ERROR_IPSEC_IKE_ERROR: DWORD = 13816; +pub const ERROR_IPSEC_IKE_CRL_FAILED: DWORD = 13817; +pub const ERROR_IPSEC_IKE_INVALID_KEY_USAGE: DWORD = 13818; +pub const ERROR_IPSEC_IKE_INVALID_CERT_TYPE: DWORD = 13819; +pub const ERROR_IPSEC_IKE_NO_PRIVATE_KEY: DWORD = 13820; +pub const ERROR_IPSEC_IKE_DH_FAIL: DWORD = 13822; +pub const ERROR_IPSEC_IKE_INVALID_HEADER: DWORD = 13824; +pub const ERROR_IPSEC_IKE_NO_POLICY: DWORD = 13825; +pub const ERROR_IPSEC_IKE_INVALID_SIGNATURE: DWORD = 13826; +pub const ERROR_IPSEC_IKE_KERBEROS_ERROR: DWORD = 13827; +pub const ERROR_IPSEC_IKE_NO_PUBLIC_KEY: DWORD = 13828; +pub const ERROR_IPSEC_IKE_PROCESS_ERR: DWORD = 13829; +pub const ERROR_IPSEC_IKE_PROCESS_ERR_SA: DWORD = 13830; +pub const ERROR_IPSEC_IKE_PROCESS_ERR_PROP: DWORD = 13831; +pub const ERROR_IPSEC_IKE_PROCESS_ERR_TRANS: DWORD = 13832; +pub const ERROR_IPSEC_IKE_PROCESS_ERR_KE: DWORD = 13833; +pub const ERROR_IPSEC_IKE_PROCESS_ERR_ID: DWORD = 13834; +pub const ERROR_IPSEC_IKE_PROCESS_ERR_CERT: DWORD = 13835; +pub const ERROR_IPSEC_IKE_PROCESS_ERR_CERT_REQ: DWORD = 13836; +pub const ERROR_IPSEC_IKE_PROCESS_ERR_HASH: DWORD = 13837; +pub const ERROR_IPSEC_IKE_PROCESS_ERR_SIG: DWORD = 13838; +pub const ERROR_IPSEC_IKE_PROCESS_ERR_NONCE: DWORD = 13839; +pub const ERROR_IPSEC_IKE_PROCESS_ERR_NOTIFY: DWORD = 13840; +pub const ERROR_IPSEC_IKE_PROCESS_ERR_DELETE: DWORD = 13841; +pub const ERROR_IPSEC_IKE_PROCESS_ERR_VENDOR: DWORD = 13842; +pub const ERROR_IPSEC_IKE_INVALID_PAYLOAD: DWORD = 13843; +pub const ERROR_IPSEC_IKE_LOAD_SOFT_SA: DWORD = 13844; +pub const ERROR_IPSEC_IKE_SOFT_SA_TORN_DOWN: DWORD = 13845; +pub const ERROR_IPSEC_IKE_INVALID_COOKIE: DWORD = 13846; +pub const ERROR_IPSEC_IKE_NO_PEER_CERT: DWORD = 13847; +pub const ERROR_IPSEC_IKE_PEER_CRL_FAILED: DWORD = 13848; +pub const ERROR_IPSEC_IKE_POLICY_CHANGE: DWORD = 13849; +pub const ERROR_IPSEC_IKE_NO_MM_POLICY: DWORD = 13850; +pub const ERROR_IPSEC_IKE_NOTCBPRIV: DWORD = 13851; +pub const ERROR_IPSEC_IKE_SECLOADFAIL: DWORD = 13852; +pub const ERROR_IPSEC_IKE_FAILSSPINIT: DWORD = 13853; +pub const ERROR_IPSEC_IKE_FAILQUERYSSP: DWORD = 13854; +pub const ERROR_IPSEC_IKE_SRVACQFAIL: DWORD = 13855; +pub const ERROR_IPSEC_IKE_SRVQUERYCRED: DWORD = 13856; +pub const ERROR_IPSEC_IKE_GETSPIFAIL: DWORD = 13857; +pub const ERROR_IPSEC_IKE_INVALID_FILTER: DWORD = 13858; +pub const ERROR_IPSEC_IKE_OUT_OF_MEMORY: DWORD = 13859; +pub const ERROR_IPSEC_IKE_ADD_UPDATE_KEY_FAILED: DWORD = 13860; +pub const ERROR_IPSEC_IKE_INVALID_POLICY: DWORD = 13861; +pub const ERROR_IPSEC_IKE_UNKNOWN_DOI: DWORD = 13862; +pub const ERROR_IPSEC_IKE_INVALID_SITUATION: DWORD = 13863; +pub const ERROR_IPSEC_IKE_DH_FAILURE: DWORD = 13864; +pub const ERROR_IPSEC_IKE_INVALID_GROUP: DWORD = 13865; +pub const ERROR_IPSEC_IKE_ENCRYPT: DWORD = 13866; +pub const ERROR_IPSEC_IKE_DECRYPT: DWORD = 13867; +pub const ERROR_IPSEC_IKE_POLICY_MATCH: DWORD = 13868; +pub const ERROR_IPSEC_IKE_UNSUPPORTED_ID: DWORD = 13869; +pub const ERROR_IPSEC_IKE_INVALID_HASH: DWORD = 13870; +pub const ERROR_IPSEC_IKE_INVALID_HASH_ALG: DWORD = 13871; +pub const ERROR_IPSEC_IKE_INVALID_HASH_SIZE: DWORD = 13872; +pub const ERROR_IPSEC_IKE_INVALID_ENCRYPT_ALG: DWORD = 13873; +pub const ERROR_IPSEC_IKE_INVALID_AUTH_ALG: DWORD = 13874; +pub const ERROR_IPSEC_IKE_INVALID_SIG: DWORD = 13875; +pub const ERROR_IPSEC_IKE_LOAD_FAILED: DWORD = 13876; +pub const ERROR_IPSEC_IKE_RPC_DELETE: DWORD = 13877; +pub const ERROR_IPSEC_IKE_BENIGN_REINIT: DWORD = 13878; +pub const ERROR_IPSEC_IKE_INVALID_RESPONDER_LIFETIME_NOTIFY: DWORD = 13879; +pub const ERROR_IPSEC_IKE_INVALID_CERT_KEYLEN: DWORD = 13881; +pub const ERROR_IPSEC_IKE_MM_LIMIT: DWORD = 13882; +pub const ERROR_IPSEC_IKE_NEGOTIATION_DISABLED: DWORD = 13883; +/*pub const ERROR_IPSEC_IKE_NEG_STATUS_END: DWORD = 13884)*/ +pub const ERROR_IPSEC_IKE_QM_LIMIT: DWORD = 13884; +pub const ERROR_IPSEC_IKE_MM_EXPIRED: DWORD = 13885; +pub const ERROR_IPSEC_IKE_PEER_MM_ASSUMED_INVALID: DWORD = 13886; +pub const ERROR_IPSEC_IKE_CERT_CHAIN_POLICY_MISMATCH: DWORD = 13887; +pub const ERROR_IPSEC_IKE_UNEXPECTED_MESSAGE_ID: DWORD = 13888; +pub const ERROR_IPSEC_IKE_INVALID_AUTH_PAYLOAD: DWORD = 13889; +pub const ERROR_IPSEC_IKE_DOS_COOKIE_SENT: DWORD = 13890; +pub const ERROR_IPSEC_IKE_SHUTTING_DOWN: DWORD = 13891; +pub const ERROR_IPSEC_IKE_CGA_AUTH_FAILED: DWORD = 13892; +pub const ERROR_IPSEC_IKE_PROCESS_ERR_NATOA: DWORD = 13893; +pub const ERROR_IPSEC_IKE_INVALID_MM_FOR_QM: DWORD = 13894; +pub const ERROR_IPSEC_IKE_QM_EXPIRED: DWORD = 13895; +pub const ERROR_IPSEC_IKE_TOO_MANY_FILTERS: DWORD = 13896; +pub const ERROR_IPSEC_IKE_NEG_STATUS_END: DWORD = 13897; +pub const ERROR_IPSEC_IKE_KILL_DUMMY_NAP_TUNNEL: DWORD = 13898; +pub const ERROR_IPSEC_IKE_INNER_IP_ASSIGNMENT_FAILURE: DWORD = 13899; +pub const ERROR_IPSEC_IKE_REQUIRE_CP_PAYLOAD_MISSING: DWORD = 13900; +pub const ERROR_IPSEC_KEY_MODULE_IMPERSONATION_NEGOTIATION_PENDING: DWORD = 13901; +pub const ERROR_IPSEC_IKE_COEXISTENCE_SUPPRESS: DWORD = 13902; +pub const ERROR_IPSEC_IKE_RATELIMIT_DROP: DWORD = 13903; +pub const ERROR_IPSEC_IKE_PEER_DOESNT_SUPPORT_MOBIKE: DWORD = 13904; +pub const ERROR_IPSEC_IKE_AUTHORIZATION_FAILURE: DWORD = 13905; +pub const ERROR_IPSEC_IKE_STRONG_CRED_AUTHORIZATION_FAILURE: DWORD = 13906; +pub const ERROR_IPSEC_IKE_AUTHORIZATION_FAILURE_WITH_OPTIONAL_RETRY: DWORD = 13907; +pub const ERROR_IPSEC_IKE_STRONG_CRED_AUTHORIZATION_AND_CERTMAP_FAILURE: DWORD = 13908; +pub const ERROR_IPSEC_IKE_NEG_STATUS_EXTENDED_END: DWORD = 13909; +pub const ERROR_IPSEC_BAD_SPI: DWORD = 13910; +pub const ERROR_IPSEC_SA_LIFETIME_EXPIRED: DWORD = 13911; +pub const ERROR_IPSEC_WRONG_SA: DWORD = 13912; +pub const ERROR_IPSEC_REPLAY_CHECK_FAILED: DWORD = 13913; +pub const ERROR_IPSEC_INVALID_PACKET: DWORD = 13914; +pub const ERROR_IPSEC_INTEGRITY_CHECK_FAILED: DWORD = 13915; +pub const ERROR_IPSEC_CLEAR_TEXT_DROP: DWORD = 13916; +pub const ERROR_IPSEC_AUTH_FIREWALL_DROP: DWORD = 13917; +pub const ERROR_IPSEC_THROTTLE_DROP: DWORD = 13918; +pub const ERROR_IPSEC_DOSP_BLOCK: DWORD = 13925; +pub const ERROR_IPSEC_DOSP_RECEIVED_MULTICAST: DWORD = 13926; +pub const ERROR_IPSEC_DOSP_INVALID_PACKET: DWORD = 13927; +pub const ERROR_IPSEC_DOSP_STATE_LOOKUP_FAILED: DWORD = 13928; +pub const ERROR_IPSEC_DOSP_MAX_ENTRIES: DWORD = 13929; +pub const ERROR_IPSEC_DOSP_KEYMOD_NOT_ALLOWED: DWORD = 13930; +pub const ERROR_IPSEC_DOSP_NOT_INSTALLED: DWORD = 13931; +pub const ERROR_IPSEC_DOSP_MAX_PER_IP_RATELIMIT_QUEUES: DWORD = 13932; +pub const ERROR_EVT_INVALID_CHANNEL_PATH: DWORD = 15000; +pub const ERROR_EVT_INVALID_QUERY: DWORD = 15001; +pub const ERROR_EVT_PUBLISHER_METADATA_NOT_FOUND: DWORD = 15002; +pub const ERROR_EVT_EVENT_TEMPLATE_NOT_FOUND: DWORD = 15003; +pub const ERROR_EVT_INVALID_PUBLISHER_NAME: DWORD = 15004; +pub const ERROR_EVT_INVALID_EVENT_DATA: DWORD = 15005; +pub const ERROR_EVT_CHANNEL_NOT_FOUND: DWORD = 15007; +pub const ERROR_EVT_MALFORMED_XML_TEXT: DWORD = 15008; +pub const ERROR_EVT_SUBSCRIPTION_TO_DIRECT_CHANNEL: DWORD = 15009; +pub const ERROR_EVT_CONFIGURATION_ERROR: DWORD = 15010; +pub const ERROR_EVT_QUERY_RESULT_STALE: DWORD = 15011; +pub const ERROR_EVT_QUERY_RESULT_INVALID_POSITION: DWORD = 15012; +pub const ERROR_EVT_NON_VALIDATING_MSXML: DWORD = 15013; +pub const ERROR_EVT_FILTER_ALREADYSCOPED: DWORD = 15014; +pub const ERROR_EVT_FILTER_NOTELTSET: DWORD = 15015; +pub const ERROR_EVT_FILTER_INVARG: DWORD = 15016; +pub const ERROR_EVT_FILTER_INVTEST: DWORD = 15017; +pub const ERROR_EVT_FILTER_INVTYPE: DWORD = 15018; +pub const ERROR_EVT_FILTER_PARSEERR: DWORD = 15019; +pub const ERROR_EVT_FILTER_UNSUPPORTEDOP: DWORD = 15020; +pub const ERROR_EVT_FILTER_UNEXPECTEDTOKEN: DWORD = 15021; +pub const ERROR_EVT_INVALID_OPERATION_OVER_ENABLED_DIRECT_CHANNEL: DWORD = 15022; +pub const ERROR_EVT_INVALID_CHANNEL_PROPERTY_VALUE: DWORD = 15023; +pub const ERROR_EVT_INVALID_PUBLISHER_PROPERTY_VALUE: DWORD = 15024; +pub const ERROR_EVT_CHANNEL_CANNOT_ACTIVATE: DWORD = 15025; +pub const ERROR_EVT_FILTER_TOO_COMPLEX: DWORD = 15026; +pub const ERROR_EVT_MESSAGE_NOT_FOUND: DWORD = 15027; +pub const ERROR_EVT_MESSAGE_ID_NOT_FOUND: DWORD = 15028; +pub const ERROR_EVT_UNRESOLVED_VALUE_INSERT: DWORD = 15029; +pub const ERROR_EVT_UNRESOLVED_PARAMETER_INSERT: DWORD = 15030; +pub const ERROR_EVT_MAX_INSERTS_REACHED: DWORD = 15031; +pub const ERROR_EVT_EVENT_DEFINITION_NOT_FOUND: DWORD = 15032; +pub const ERROR_EVT_MESSAGE_LOCALE_NOT_FOUND: DWORD = 15033; +pub const ERROR_EVT_VERSION_TOO_OLD: DWORD = 15034; +pub const ERROR_EVT_VERSION_TOO_NEW: DWORD = 15035; +pub const ERROR_EVT_CANNOT_OPEN_CHANNEL_OF_QUERY: DWORD = 15036; +pub const ERROR_EVT_PUBLISHER_DISABLED: DWORD = 15037; +pub const ERROR_EVT_FILTER_OUT_OF_RANGE: DWORD = 15038; +pub const ERROR_EC_SUBSCRIPTION_CANNOT_ACTIVATE: DWORD = 15080; +pub const ERROR_EC_LOG_DISABLED: DWORD = 15081; +pub const ERROR_EC_CIRCULAR_FORWARDING: DWORD = 15082; +pub const ERROR_EC_CREDSTORE_FULL: DWORD = 15083; +pub const ERROR_EC_CRED_NOT_FOUND: DWORD = 15084; +pub const ERROR_EC_NO_ACTIVE_CHANNEL: DWORD = 15085; +pub const ERROR_MUI_FILE_NOT_FOUND: DWORD = 15100; +pub const ERROR_MUI_INVALID_FILE: DWORD = 15101; +pub const ERROR_MUI_INVALID_RC_CONFIG: DWORD = 15102; +pub const ERROR_MUI_INVALID_LOCALE_NAME: DWORD = 15103; +pub const ERROR_MUI_INVALID_ULTIMATEFALLBACK_NAME: DWORD = 15104; +pub const ERROR_MUI_FILE_NOT_LOADED: DWORD = 15105; +pub const ERROR_RESOURCE_ENUM_USER_STOP: DWORD = 15106; +pub const ERROR_MUI_INTLSETTINGS_UILANG_NOT_INSTALLED: DWORD = 15107; +pub const ERROR_MUI_INTLSETTINGS_INVALID_LOCALE_NAME: DWORD = 15108; +pub const ERROR_MRM_RUNTIME_NO_DEFAULT_OR_NEUTRAL_RESOURCE: DWORD = 15110; +pub const ERROR_MRM_INVALID_PRICONFIG: DWORD = 15111; +pub const ERROR_MRM_INVALID_FILE_TYPE: DWORD = 15112; +pub const ERROR_MRM_UNKNOWN_QUALIFIER: DWORD = 15113; +pub const ERROR_MRM_INVALID_QUALIFIER_VALUE: DWORD = 15114; +pub const ERROR_MRM_NO_CANDIDATE: DWORD = 15115; +pub const ERROR_MRM_NO_MATCH_OR_DEFAULT_CANDIDATE: DWORD = 15116; +pub const ERROR_MRM_RESOURCE_TYPE_MISMATCH: DWORD = 15117; +pub const ERROR_MRM_DUPLICATE_MAP_NAME: DWORD = 15118; +pub const ERROR_MRM_DUPLICATE_ENTRY: DWORD = 15119; +pub const ERROR_MRM_INVALID_RESOURCE_IDENTIFIER: DWORD = 15120; +pub const ERROR_MRM_FILEPATH_TOO_LONG: DWORD = 15121; +pub const ERROR_MRM_UNSUPPORTED_DIRECTORY_TYPE: DWORD = 15122; +pub const ERROR_MRM_INVALID_PRI_FILE: DWORD = 15126; +pub const ERROR_MRM_NAMED_RESOURCE_NOT_FOUND: DWORD = 15127; +pub const ERROR_MRM_MAP_NOT_FOUND: DWORD = 15135; +pub const ERROR_MRM_UNSUPPORTED_PROFILE_TYPE: DWORD = 15136; +pub const ERROR_MRM_INVALID_QUALIFIER_OPERATOR: DWORD = 15137; +pub const ERROR_MRM_INDETERMINATE_QUALIFIER_VALUE: DWORD = 15138; +pub const ERROR_MRM_AUTOMERGE_ENABLED: DWORD = 15139; +pub const ERROR_MRM_TOO_MANY_RESOURCES: DWORD = 15140; +pub const ERROR_MCA_INVALID_CAPABILITIES_STRING: DWORD = 15200; +pub const ERROR_MCA_INVALID_VCP_VERSION: DWORD = 15201; +pub const ERROR_MCA_MONITOR_VIOLATES_MCCS_SPECIFICATION: DWORD = 15202; +pub const ERROR_MCA_MCCS_VERSION_MISMATCH: DWORD = 15203; +pub const ERROR_MCA_UNSUPPORTED_MCCS_VERSION: DWORD = 15204; +pub const ERROR_MCA_INTERNAL_ERROR: DWORD = 15205; +pub const ERROR_MCA_INVALID_TECHNOLOGY_TYPE_RETURNED: DWORD = 15206; +pub const ERROR_MCA_UNSUPPORTED_COLOR_TEMPERATURE: DWORD = 15207; +pub const ERROR_AMBIGUOUS_SYSTEM_DEVICE: DWORD = 15250; +pub const ERROR_SYSTEM_DEVICE_NOT_FOUND: DWORD = 15299; +pub const ERROR_HASH_NOT_SUPPORTED: DWORD = 15300; +pub const ERROR_HASH_NOT_PRESENT: DWORD = 15301; +pub const ERROR_SECONDARY_IC_PROVIDER_NOT_REGISTERED: DWORD = 15321; +pub const ERROR_GPIO_CLIENT_INFORMATION_INVALID: DWORD = 15322; +pub const ERROR_GPIO_VERSION_NOT_SUPPORTED: DWORD = 15323; +pub const ERROR_GPIO_INVALID_REGISTRATION_PACKET: DWORD = 15324; +pub const ERROR_GPIO_OPERATION_DENIED: DWORD = 15325; +pub const ERROR_GPIO_INCOMPATIBLE_CONNECT_MODE: DWORD = 15326; +pub const ERROR_GPIO_INTERRUPT_ALREADY_UNMASKED: DWORD = 15327; +pub const ERROR_CANNOT_SWITCH_RUNLEVEL: DWORD = 15400; +pub const ERROR_INVALID_RUNLEVEL_SETTING: DWORD = 15401; +pub const ERROR_RUNLEVEL_SWITCH_TIMEOUT: DWORD = 15402; +pub const ERROR_RUNLEVEL_SWITCH_AGENT_TIMEOUT: DWORD = 15403; +pub const ERROR_RUNLEVEL_SWITCH_IN_PROGRESS: DWORD = 15404; +pub const ERROR_SERVICES_FAILED_AUTOSTART: DWORD = 15405; +pub const ERROR_COM_TASK_STOP_PENDING: DWORD = 15501; +pub const ERROR_INSTALL_OPEN_PACKAGE_FAILED: DWORD = 15600; +pub const ERROR_INSTALL_PACKAGE_NOT_FOUND: DWORD = 15601; +pub const ERROR_INSTALL_INVALID_PACKAGE: DWORD = 15602; +pub const ERROR_INSTALL_RESOLVE_DEPENDENCY_FAILED: DWORD = 15603; +pub const ERROR_INSTALL_OUT_OF_DISK_SPACE: DWORD = 15604; +pub const ERROR_INSTALL_NETWORK_FAILURE: DWORD = 15605; +pub const ERROR_INSTALL_REGISTRATION_FAILURE: DWORD = 15606; +pub const ERROR_INSTALL_DEREGISTRATION_FAILURE: DWORD = 15607; +pub const ERROR_INSTALL_CANCEL: DWORD = 15608; +pub const ERROR_INSTALL_FAILED: DWORD = 15609; +pub const ERROR_REMOVE_FAILED: DWORD = 15610; +pub const ERROR_PACKAGE_ALREADY_EXISTS: DWORD = 15611; +pub const ERROR_NEEDS_REMEDIATION: DWORD = 15612; +pub const ERROR_INSTALL_PREREQUISITE_FAILED: DWORD = 15613; +pub const ERROR_PACKAGE_REPOSITORY_CORRUPTED: DWORD = 15614; +pub const ERROR_INSTALL_POLICY_FAILURE: DWORD = 15615; +pub const ERROR_PACKAGE_UPDATING: DWORD = 15616; +pub const ERROR_DEPLOYMENT_BLOCKED_BY_POLICY: DWORD = 15617; +pub const ERROR_PACKAGES_IN_USE: DWORD = 15618; +pub const ERROR_RECOVERY_FILE_CORRUPT: DWORD = 15619; +pub const ERROR_INVALID_STAGED_SIGNATURE: DWORD = 15620; +pub const ERROR_DELETING_EXISTING_APPLICATIONDATA_STORE_FAILED: DWORD = 15621; +pub const ERROR_INSTALL_PACKAGE_DOWNGRADE: DWORD = 15622; +pub const ERROR_SYSTEM_NEEDS_REMEDIATION: DWORD = 15623; +pub const ERROR_APPX_INTEGRITY_FAILURE_CLR_NGEN: DWORD = 15624; +pub const ERROR_RESILIENCY_FILE_CORRUPT: DWORD = 15625; +pub const ERROR_INSTALL_FIREWALL_SERVICE_NOT_RUNNING: DWORD = 15626; +pub const ERROR_STATE_LOAD_STORE_FAILED: DWORD = 15800; +pub const ERROR_STATE_GET_VERSION_FAILED: DWORD = 15801; +pub const ERROR_STATE_SET_VERSION_FAILED: DWORD = 15802; +pub const ERROR_STATE_STRUCTURED_RESET_FAILED: DWORD = 15803; +pub const ERROR_STATE_OPEN_CONTAINER_FAILED: DWORD = 15804; +pub const ERROR_STATE_CREATE_CONTAINER_FAILED: DWORD = 15805; +pub const ERROR_STATE_DELETE_CONTAINER_FAILED: DWORD = 15806; +pub const ERROR_STATE_READ_SETTING_FAILED: DWORD = 15807; +pub const ERROR_STATE_WRITE_SETTING_FAILED: DWORD = 15808; +pub const ERROR_STATE_DELETE_SETTING_FAILED: DWORD = 15809; +pub const ERROR_STATE_QUERY_SETTING_FAILED: DWORD = 15810; +pub const ERROR_STATE_READ_COMPOSITE_SETTING_FAILED: DWORD = 15811; +pub const ERROR_STATE_WRITE_COMPOSITE_SETTING_FAILED: DWORD = 15812; +pub const ERROR_STATE_ENUMERATE_CONTAINER_FAILED: DWORD = 15813; +pub const ERROR_STATE_ENUMERATE_SETTINGS_FAILED: DWORD = 15814; +pub const ERROR_STATE_COMPOSITE_SETTING_VALUE_SIZE_LIMIT_EXCEEDED: DWORD = 15815; +pub const ERROR_STATE_SETTING_VALUE_SIZE_LIMIT_EXCEEDED: DWORD = 15816; +pub const ERROR_STATE_SETTING_NAME_SIZE_LIMIT_EXCEEDED: DWORD = 15817; +pub const ERROR_STATE_CONTAINER_NAME_SIZE_LIMIT_EXCEEDED: DWORD = 15818; +pub const ERROR_API_UNAVAILABLE: DWORD = 15841; +pub const ERROR_AUDITING_DISABLED: DWORD = 0xC0090001; +pub const ERROR_ALL_SIDS_FILTERED: DWORD = 0xC0090002; + +pub const WSABASEERR: c_int = 10000; +pub const WSAEINTR: c_int = WSABASEERR + 4; +pub const WSAEBADF: c_int = WSABASEERR + 9; +pub const WSAEACCES: c_int = WSABASEERR + 13; +pub const WSAEFAULT: c_int = WSABASEERR + 14; +pub const WSAEINVAL: c_int = WSABASEERR + 22; +pub const WSAEMFILE: c_int = WSABASEERR + 24; +pub const WSAEWOULDBLOCK: c_int = WSABASEERR + 35; +pub const WSAEINPROGRESS: c_int = WSABASEERR + 36; +pub const WSAEALREADY: c_int = WSABASEERR + 37; +pub const WSAENOTSOCK: c_int = WSABASEERR + 38; +pub const WSAEDESTADDRREQ: c_int = WSABASEERR + 39; +pub const WSAEMSGSIZE: c_int = WSABASEERR + 40; +pub const WSAEPROTOTYPE: c_int = WSABASEERR + 41; +pub const WSAENOPROTOOPT: c_int = WSABASEERR + 42; +pub const WSAEPROTONOSUPPORT: c_int = WSABASEERR + 43; +pub const WSAESOCKTNOSUPPORT: c_int = WSABASEERR + 44; +pub const WSAEOPNOTSUPP: c_int = WSABASEERR + 45; +pub const WSAEPFNOSUPPORT: c_int = WSABASEERR + 46; +pub const WSAEAFNOSUPPORT: c_int = WSABASEERR + 47; +pub const WSAEADDRINUSE: c_int = WSABASEERR + 48; +pub const WSAEADDRNOTAVAIL: c_int = WSABASEERR + 49; +pub const WSAENETDOWN: c_int = WSABASEERR + 50; +pub const WSAENETUNREACH: c_int = WSABASEERR + 51; +pub const WSAENETRESET: c_int = WSABASEERR + 52; +pub const WSAECONNABORTED: c_int = WSABASEERR + 53; +pub const WSAECONNRESET: c_int = WSABASEERR + 54; +pub const WSAENOBUFS: c_int = WSABASEERR + 55; +pub const WSAEISCONN: c_int = WSABASEERR + 56; +pub const WSAENOTCONN: c_int = WSABASEERR + 57; +pub const WSAESHUTDOWN: c_int = WSABASEERR + 58; +pub const WSAETOOMANYREFS: c_int = WSABASEERR + 59; +pub const WSAETIMEDOUT: c_int = WSABASEERR + 60; +pub const WSAECONNREFUSED: c_int = WSABASEERR + 61; +pub const WSAELOOP: c_int = WSABASEERR + 62; +pub const WSAENAMETOOLONG: c_int = WSABASEERR + 63; +pub const WSAEHOSTDOWN: c_int = WSABASEERR + 64; +pub const WSAEHOSTUNREACH: c_int = WSABASEERR + 65; +pub const WSAENOTEMPTY: c_int = WSABASEERR + 66; +pub const WSAEPROCLIM: c_int = WSABASEERR + 67; +pub const WSAEUSERS: c_int = WSABASEERR + 68; +pub const WSAEDQUOT: c_int = WSABASEERR + 69; +pub const WSAESTALE: c_int = WSABASEERR + 70; +pub const WSAEREMOTE: c_int = WSABASEERR + 71; +pub const WSASYSNOTREADY: c_int = WSABASEERR + 91; +pub const WSAVERNOTSUPPORTED: c_int = WSABASEERR + 92; +pub const WSANOTINITIALISED: c_int = WSABASEERR + 93; +pub const WSAEDISCON: c_int = WSABASEERR + 101; +pub const WSAENOMORE: c_int = WSABASEERR + 102; +pub const WSAECANCELLED: c_int = WSABASEERR + 103; +pub const WSAEINVALIDPROCTABLE: c_int = WSABASEERR + 104; +pub const WSAEINVALIDPROVIDER: c_int = WSABASEERR + 105; +pub const WSAEPROVIDERFAILEDINIT: c_int = WSABASEERR + 106; +pub const WSASYSCALLFAILURE: c_int = WSABASEERR + 107; +pub const WSASERVICE_NOT_FOUND: c_int = WSABASEERR + 108; +pub const WSATYPE_NOT_FOUND: c_int = WSABASEERR + 109; +pub const WSA_E_NO_MORE: c_int = WSABASEERR + 110; +pub const WSA_E_CANCELLED: c_int = WSABASEERR + 111; +pub const WSAEREFUSED: c_int = WSABASEERR + 112; +pub const WSAHOST_NOT_FOUND: c_int = WSABASEERR + 1001; +pub const WSATRY_AGAIN: c_int = WSABASEERR + 1002; +pub const WSANO_RECOVERY: c_int = WSABASEERR + 1003; +pub const WSANO_DATA: c_int = WSABASEERR + 1004; +pub const WSA_QOS_RECEIVERS: c_int = WSABASEERR + 1005; +pub const WSA_QOS_SENDERS: c_int = WSABASEERR + 1006; +pub const WSA_QOS_NO_SENDERS: c_int = WSABASEERR + 1007; +pub const WSA_QOS_NO_RECEIVERS: c_int = WSABASEERR + 1008; +pub const WSA_QOS_REQUEST_CONFIRMED: c_int = WSABASEERR + 1009; +pub const WSA_QOS_ADMISSION_FAILURE: c_int = WSABASEERR + 1010; +pub const WSA_QOS_POLICY_FAILURE: c_int = WSABASEERR + 1011; +pub const WSA_QOS_BAD_STYLE: c_int = WSABASEERR + 1012; +pub const WSA_QOS_BAD_OBJECT: c_int = WSABASEERR + 1013; +pub const WSA_QOS_TRAFFIC_CTRL_ERROR: c_int = WSABASEERR + 1014; +pub const WSA_QOS_GENERIC_ERROR: c_int = WSABASEERR + 1015; +pub const WSA_QOS_ESERVICETYPE: c_int = WSABASEERR + 1016; +pub const WSA_QOS_EFLOWSPEC: c_int = WSABASEERR + 1017; +pub const WSA_QOS_EPROVSPECBUF: c_int = WSABASEERR + 1018; +pub const WSA_QOS_EFILTERSTYLE: c_int = WSABASEERR + 1019; +pub const WSA_QOS_EFILTERTYPE: c_int = WSABASEERR + 1020; +pub const WSA_QOS_EFILTERCOUNT: c_int = WSABASEERR + 1021; +pub const WSA_QOS_EOBJLENGTH: c_int = WSABASEERR + 1022; +pub const WSA_QOS_EFLOWCOUNT: c_int = WSABASEERR + 1023; +pub const WSA_QOS_EUNKNOWNPSOBJ: c_int = WSABASEERR + 1024; +pub const WSA_QOS_EUNKOWNPSOBJ: c_int = WSA_QOS_EUNKNOWNPSOBJ; +pub const WSA_QOS_EPOLICYOBJ: c_int = WSABASEERR + 1025; +pub const WSA_QOS_EFLOWDESC: c_int = WSABASEERR + 1026; +pub const WSA_QOS_EPSFLOWSPEC: c_int = WSABASEERR + 1027; +pub const WSA_QOS_EPSFILTERSPEC: c_int = WSABASEERR + 1028; +pub const WSA_QOS_ESDMODEOBJ: c_int = WSABASEERR + 1029; +pub const WSA_QOS_ESHAPERATEOBJ: c_int = WSABASEERR + 1030; +pub const WSA_QOS_RESERVED_PETYPE: c_int = WSABASEERR + 1031; diff --git a/library/std/src/sys/windows/fs.rs b/library/std/src/sys/windows/fs.rs index 2b6143de960..c677adae688 100644 --- a/library/std/src/sys/windows/fs.rs +++ b/library/std/src/sys/windows/fs.rs @@ -514,7 +514,7 @@ impl File { } _ => { return Err(io::Error::new_const( - io::ErrorKind::Other, + io::ErrorKind::Uncategorized, &"Unsupported reparse point type", )); } @@ -961,9 +961,8 @@ pub fn try_exists(path: &Path) -> io::Result<bool> { // `ERROR_SHARING_VIOLATION` means that the file has been locked by // another process. This is often temporary so we simply report it // as the file existing. - io::ErrorKind::Other if e.raw_os_error() == Some(c::ERROR_SHARING_VIOLATION as i32) => { - Ok(true) - } + _ if e.raw_os_error() == Some(c::ERROR_SHARING_VIOLATION as i32) => Ok(true), + // Other errors such as `ERROR_ACCESS_DENIED` may indicate that the // file exists. However, these types of errors are usually more // permanent so we report them here. diff --git a/library/std/src/sys/windows/mod.rs b/library/std/src/sys/windows/mod.rs index f23e874f249..28fec817f86 100644 --- a/library/std/src/sys/windows/mod.rs +++ b/library/std/src/sys/windows/mod.rs @@ -61,16 +61,18 @@ pub unsafe fn cleanup() { } pub fn decode_error_kind(errno: i32) -> ErrorKind { + use ErrorKind::*; + match errno as c::DWORD { - c::ERROR_ACCESS_DENIED => return ErrorKind::PermissionDenied, - c::ERROR_ALREADY_EXISTS => return ErrorKind::AlreadyExists, - c::ERROR_FILE_EXISTS => return ErrorKind::AlreadyExists, - c::ERROR_BROKEN_PIPE => return ErrorKind::BrokenPipe, - c::ERROR_FILE_NOT_FOUND => return ErrorKind::NotFound, - c::ERROR_PATH_NOT_FOUND => return ErrorKind::NotFound, - c::ERROR_NO_DATA => return ErrorKind::BrokenPipe, - c::ERROR_INVALID_PARAMETER => return ErrorKind::InvalidInput, - c::ERROR_NOT_ENOUGH_MEMORY | c::ERROR_OUTOFMEMORY => return ErrorKind::OutOfMemory, + c::ERROR_ACCESS_DENIED => return PermissionDenied, + c::ERROR_ALREADY_EXISTS => return AlreadyExists, + c::ERROR_FILE_EXISTS => return AlreadyExists, + c::ERROR_BROKEN_PIPE => return BrokenPipe, + c::ERROR_FILE_NOT_FOUND => return NotFound, + c::ERROR_PATH_NOT_FOUND => return NotFound, + c::ERROR_NO_DATA => return BrokenPipe, + c::ERROR_INVALID_PARAMETER => return InvalidInput, + c::ERROR_NOT_ENOUGH_MEMORY | c::ERROR_OUTOFMEMORY => return OutOfMemory, c::ERROR_SEM_TIMEOUT | c::WAIT_TIMEOUT | c::ERROR_DRIVER_CANCEL_TIMEOUT @@ -86,24 +88,42 @@ pub fn decode_error_kind(errno: i32) -> ErrorKind { | c::DNS_ERROR_RECORD_TIMED_OUT | c::ERROR_IPSEC_IKE_TIMED_OUT | c::ERROR_RUNLEVEL_SWITCH_TIMEOUT - | c::ERROR_RUNLEVEL_SWITCH_AGENT_TIMEOUT => return ErrorKind::TimedOut, - c::ERROR_CALL_NOT_IMPLEMENTED => return ErrorKind::Unsupported, + | c::ERROR_RUNLEVEL_SWITCH_AGENT_TIMEOUT => return TimedOut, + c::ERROR_CALL_NOT_IMPLEMENTED => return Unsupported, + c::ERROR_HOST_UNREACHABLE => return HostUnreachable, + c::ERROR_NETWORK_UNREACHABLE => return NetworkUnreachable, + c::ERROR_DIRECTORY => return NotADirectory, + c::ERROR_DIRECTORY_NOT_SUPPORTED => return IsADirectory, + c::ERROR_DIR_NOT_EMPTY => return DirectoryNotEmpty, + c::ERROR_WRITE_PROTECT => return ReadOnlyFilesystem, + c::ERROR_DISK_FULL | c::ERROR_HANDLE_DISK_FULL => return StorageFull, + c::ERROR_SEEK_ON_DEVICE => return NotSeekable, + c::ERROR_DISK_QUOTA_EXCEEDED => return FilesystemQuotaExceeded, + c::ERROR_FILE_TOO_LARGE => return FileTooLarge, + c::ERROR_BUSY => return ResourceBusy, + c::ERROR_POSSIBLE_DEADLOCK => return Deadlock, + c::ERROR_NOT_SAME_DEVICE => return CrossesDevices, + c::ERROR_TOO_MANY_LINKS => return TooManyLinks, + c::ERROR_FILENAME_EXCED_RANGE => return FilenameTooLong, _ => {} } match errno { - c::WSAEACCES => ErrorKind::PermissionDenied, - c::WSAEADDRINUSE => ErrorKind::AddrInUse, - c::WSAEADDRNOTAVAIL => ErrorKind::AddrNotAvailable, - c::WSAECONNABORTED => ErrorKind::ConnectionAborted, - c::WSAECONNREFUSED => ErrorKind::ConnectionRefused, - c::WSAECONNRESET => ErrorKind::ConnectionReset, - c::WSAEINVAL => ErrorKind::InvalidInput, - c::WSAENOTCONN => ErrorKind::NotConnected, - c::WSAEWOULDBLOCK => ErrorKind::WouldBlock, - c::WSAETIMEDOUT => ErrorKind::TimedOut, + c::WSAEACCES => PermissionDenied, + c::WSAEADDRINUSE => AddrInUse, + c::WSAEADDRNOTAVAIL => AddrNotAvailable, + c::WSAECONNABORTED => ConnectionAborted, + c::WSAECONNREFUSED => ConnectionRefused, + c::WSAECONNRESET => ConnectionReset, + c::WSAEINVAL => InvalidInput, + c::WSAENOTCONN => NotConnected, + c::WSAEWOULDBLOCK => WouldBlock, + c::WSAETIMEDOUT => TimedOut, + c::WSAEHOSTUNREACH => HostUnreachable, + c::WSAENETDOWN => NetworkDown, + c::WSAENETUNREACH => NetworkUnreachable, - _ => ErrorKind::Other, + _ => Uncategorized, } } diff --git a/library/std/src/sys/windows/mutex.rs b/library/std/src/sys/windows/mutex.rs index 12c5ea741f9..56f91ebe582 100644 --- a/library/std/src/sys/windows/mutex.rs +++ b/library/std/src/sys/windows/mutex.rs @@ -1,6 +1,6 @@ //! System Mutexes //! -//! The Windows implementation of mutexes is a little odd and it may not be +//! The Windows implementation of mutexes is a little odd and it might not be //! immediately obvious what's going on. The primary oddness is that SRWLock is //! used instead of CriticalSection, and this is done because: //! diff --git a/library/std/src/sys/windows/net.rs b/library/std/src/sys/windows/net.rs index 1ad13254c08..9cea5c5e63a 100644 --- a/library/std/src/sys/windows/net.rs +++ b/library/std/src/sys/windows/net.rs @@ -12,7 +12,7 @@ use crate::sys_common::net; use crate::sys_common::{AsInner, FromInner, IntoInner}; use crate::time::Duration; -use libc::{c_int, c_long, c_ulong, c_void}; +use libc::{c_int, c_long, c_ulong}; pub type wrlen_t = i32; @@ -93,153 +93,177 @@ where impl Socket { pub fn new(addr: &SocketAddr, ty: c_int) -> io::Result<Socket> { - let fam = match *addr { + let family = match *addr { SocketAddr::V4(..) => c::AF_INET, SocketAddr::V6(..) => c::AF_INET6, }; let socket = unsafe { - match c::WSASocketW( - fam, + c::WSASocketW( + family, ty, 0, ptr::null_mut(), 0, c::WSA_FLAG_OVERLAPPED | c::WSA_FLAG_NO_HANDLE_INHERIT, - ) { - c::INVALID_SOCKET => match c::WSAGetLastError() { - c::WSAEPROTOTYPE | c::WSAEINVAL => { - match c::WSASocketW(fam, ty, 0, ptr::null_mut(), 0, c::WSA_FLAG_OVERLAPPED) - { - c::INVALID_SOCKET => Err(last_error()), - n => { - let s = Socket(n); - s.set_no_inherit()?; - Ok(s) - } - } - } - n => Err(io::Error::from_raw_os_error(n)), - }, - n => Ok(Socket(n)), + ) + }; + + if socket != c::INVALID_SOCKET { + Ok(Self(socket)) + } else { + let error = unsafe { c::WSAGetLastError() }; + + if error != c::WSAEPROTOTYPE && error != c::WSAEINVAL { + return Err(io::Error::from_raw_os_error(error)); + } + + let socket = + unsafe { c::WSASocketW(family, ty, 0, ptr::null_mut(), 0, c::WSA_FLAG_OVERLAPPED) }; + + if socket == c::INVALID_SOCKET { + return Err(last_error()); } - }?; - Ok(socket) + + let socket = Self(socket); + socket.set_no_inherit()?; + Ok(socket) + } } pub fn connect_timeout(&self, addr: &SocketAddr, timeout: Duration) -> io::Result<()> { self.set_nonblocking(true)?; - let r = unsafe { + let result = { let (addrp, len) = addr.into_inner(); - cvt(c::connect(self.0, addrp, len)) + let result = unsafe { c::connect(self.0, addrp, len) }; + cvt(result).map(drop) }; self.set_nonblocking(false)?; - match r { - Ok(_) => return Ok(()), - Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => {} - Err(e) => return Err(e), - } - - if timeout.as_secs() == 0 && timeout.subsec_nanos() == 0 { - return Err(io::Error::new_const( - io::ErrorKind::InvalidInput, - &"cannot set a 0 duration timeout", - )); - } - - let mut timeout = c::timeval { - tv_sec: timeout.as_secs() as c_long, - tv_usec: (timeout.subsec_nanos() / 1000) as c_long, - }; - if timeout.tv_sec == 0 && timeout.tv_usec == 0 { - timeout.tv_usec = 1; - } + match result { + Err(ref error) if error.kind() == io::ErrorKind::WouldBlock => { + if timeout.as_secs() == 0 && timeout.subsec_nanos() == 0 { + return Err(io::Error::new_const( + io::ErrorKind::InvalidInput, + &"cannot set a 0 duration timeout", + )); + } - let fds = unsafe { - let mut fds = mem::zeroed::<c::fd_set>(); - fds.fd_count = 1; - fds.fd_array[0] = self.0; - fds - }; + let mut timeout = c::timeval { + tv_sec: timeout.as_secs() as c_long, + tv_usec: (timeout.subsec_nanos() / 1000) as c_long, + }; - let mut writefds = fds; - let mut errorfds = fds; + if timeout.tv_sec == 0 && timeout.tv_usec == 0 { + timeout.tv_usec = 1; + } - let n = - unsafe { cvt(c::select(1, ptr::null_mut(), &mut writefds, &mut errorfds, &timeout))? }; + let fds = { + let mut fds = unsafe { mem::zeroed::<c::fd_set>() }; + fds.fd_count = 1; + fds.fd_array[0] = self.0; + fds + }; + + let mut writefds = fds; + let mut errorfds = fds; + + let count = { + let result = unsafe { + c::select(1, ptr::null_mut(), &mut writefds, &mut errorfds, &timeout) + }; + cvt(result)? + }; + + match count { + 0 => { + Err(io::Error::new_const(io::ErrorKind::TimedOut, &"connection timed out")) + } + _ => { + if writefds.fd_count != 1 { + if let Some(e) = self.take_error()? { + return Err(e); + } + } - match n { - 0 => Err(io::Error::new_const(io::ErrorKind::TimedOut, &"connection timed out")), - _ => { - if writefds.fd_count != 1 { - if let Some(e) = self.take_error()? { - return Err(e); + Ok(()) } } - Ok(()) } + _ => result, } } pub fn accept(&self, storage: *mut c::SOCKADDR, len: *mut c_int) -> io::Result<Socket> { - let socket = unsafe { - match c::accept(self.0, storage, len) { - c::INVALID_SOCKET => Err(last_error()), - n => Ok(Socket(n)), - } - }?; - Ok(socket) + let socket = unsafe { c::accept(self.0, storage, len) }; + + match socket { + c::INVALID_SOCKET => Err(last_error()), + _ => Ok(Self(socket)), + } } pub fn duplicate(&self) -> io::Result<Socket> { + let mut info = unsafe { mem::zeroed::<c::WSAPROTOCOL_INFO>() }; + let result = unsafe { c::WSADuplicateSocketW(self.0, c::GetCurrentProcessId(), &mut info) }; + cvt(result)?; let socket = unsafe { - let mut info: c::WSAPROTOCOL_INFO = mem::zeroed(); - cvt(c::WSADuplicateSocketW(self.0, c::GetCurrentProcessId(), &mut info))?; - - match c::WSASocketW( + c::WSASocketW( info.iAddressFamily, info.iSocketType, info.iProtocol, &mut info, 0, c::WSA_FLAG_OVERLAPPED | c::WSA_FLAG_NO_HANDLE_INHERIT, - ) { - c::INVALID_SOCKET => match c::WSAGetLastError() { - c::WSAEPROTOTYPE | c::WSAEINVAL => { - match c::WSASocketW( - info.iAddressFamily, - info.iSocketType, - info.iProtocol, - &mut info, - 0, - c::WSA_FLAG_OVERLAPPED, - ) { - c::INVALID_SOCKET => Err(last_error()), - n => { - let s = Socket(n); - s.set_no_inherit()?; - Ok(s) - } - } - } - n => Err(io::Error::from_raw_os_error(n)), - }, - n => Ok(Socket(n)), + ) + }; + + if socket != c::INVALID_SOCKET { + Ok(Self(socket)) + } else { + let error = unsafe { c::WSAGetLastError() }; + + if error != c::WSAEPROTOTYPE && error != c::WSAEINVAL { + return Err(io::Error::from_raw_os_error(error)); + } + + let socket = unsafe { + c::WSASocketW( + info.iAddressFamily, + info.iSocketType, + info.iProtocol, + &mut info, + 0, + c::WSA_FLAG_OVERLAPPED, + ) + }; + + if socket == c::INVALID_SOCKET { + return Err(last_error()); } - }?; - Ok(socket) + + let socket = Self(socket); + socket.set_no_inherit()?; + Ok(socket) + } } fn recv_with_flags(&self, buf: &mut [u8], flags: c_int) -> io::Result<usize> { // On unix when a socket is shut down all further reads return 0, so we // do the same on windows to map a shut down socket to returning EOF. - let len = cmp::min(buf.len(), i32::MAX as usize) as i32; - unsafe { - match c::recv(self.0, buf.as_mut_ptr() as *mut c_void, len, flags) { - -1 if c::WSAGetLastError() == c::WSAESHUTDOWN => Ok(0), - -1 => Err(last_error()), - n => Ok(n as usize), + let length = cmp::min(buf.len(), i32::MAX as usize) as i32; + let result = unsafe { c::recv(self.0, buf.as_mut_ptr() as *mut _, length, flags) }; + + match result { + c::SOCKET_ERROR => { + let error = unsafe { c::WSAGetLastError() }; + + if error == c::WSAESHUTDOWN { + Ok(0) + } else { + Err(io::Error::from_raw_os_error(error)) + } } + _ => Ok(result as usize), } } @@ -250,23 +274,31 @@ impl Socket { pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> { // On unix when a socket is shut down all further reads return 0, so we // do the same on windows to map a shut down socket to returning EOF. - let len = cmp::min(bufs.len(), c::DWORD::MAX as usize) as c::DWORD; + let length = cmp::min(bufs.len(), c::DWORD::MAX as usize) as c::DWORD; let mut nread = 0; let mut flags = 0; - unsafe { - let ret = c::WSARecv( + let result = unsafe { + c::WSARecv( self.0, bufs.as_mut_ptr() as *mut c::WSABUF, - len, + length, &mut nread, &mut flags, ptr::null_mut(), ptr::null_mut(), - ); - match ret { - 0 => Ok(nread as usize), - _ if c::WSAGetLastError() == c::WSAESHUTDOWN => Ok(0), - _ => Err(last_error()), + ) + }; + + match result { + 0 => Ok(nread as usize), + _ => { + let error = unsafe { c::WSAGetLastError() }; + + if error == c::WSAESHUTDOWN { + Ok(0) + } else { + Err(io::Error::from_raw_os_error(error)) + } } } } @@ -285,27 +317,34 @@ impl Socket { buf: &mut [u8], flags: c_int, ) -> io::Result<(usize, SocketAddr)> { - let mut storage: c::SOCKADDR_STORAGE_LH = unsafe { mem::zeroed() }; + let mut storage = unsafe { mem::zeroed::<c::SOCKADDR_STORAGE_LH>() }; let mut addrlen = mem::size_of_val(&storage) as c::socklen_t; - let len = cmp::min(buf.len(), <wrlen_t>::MAX as usize) as wrlen_t; + let length = cmp::min(buf.len(), <wrlen_t>::MAX as usize) as wrlen_t; // On unix when a socket is shut down all further reads return 0, so we // do the same on windows to map a shut down socket to returning EOF. - unsafe { - match c::recvfrom( + let result = unsafe { + c::recvfrom( self.0, - buf.as_mut_ptr() as *mut c_void, - len, + buf.as_mut_ptr() as *mut _, + length, flags, &mut storage as *mut _ as *mut _, &mut addrlen, - ) { - -1 if c::WSAGetLastError() == c::WSAESHUTDOWN => { + ) + }; + + match result { + c::SOCKET_ERROR => { + let error = unsafe { c::WSAGetLastError() }; + + if error == c::WSAESHUTDOWN { Ok((0, net::sockaddr_to_addr(&storage, addrlen as usize)?)) + } else { + Err(io::Error::from_raw_os_error(error)) } - -1 => Err(last_error()), - n => Ok((n as usize, net::sockaddr_to_addr(&storage, addrlen as usize)?)), } + _ => Ok((result as usize, net::sockaddr_to_addr(&storage, addrlen as usize)?)), } } @@ -318,20 +357,20 @@ impl Socket { } pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> { - let len = cmp::min(bufs.len(), c::DWORD::MAX as usize) as c::DWORD; + let length = cmp::min(bufs.len(), c::DWORD::MAX as usize) as c::DWORD; let mut nwritten = 0; - unsafe { - cvt(c::WSASend( + let result = unsafe { + c::WSASend( self.0, - bufs.as_ptr() as *const c::WSABUF as *mut c::WSABUF, - len, + bufs.as_ptr() as *const c::WSABUF as *mut _, + length, &mut nwritten, 0, ptr::null_mut(), ptr::null_mut(), - ))?; - } - Ok(nwritten as usize) + ) + }; + cvt(result).map(|_| nwritten as usize) } #[inline] @@ -384,14 +423,14 @@ impl Socket { Shutdown::Read => c::SD_RECEIVE, Shutdown::Both => c::SD_BOTH, }; - cvt(unsafe { c::shutdown(self.0, how) })?; - Ok(()) + let result = unsafe { c::shutdown(self.0, how) }; + cvt(result).map(drop) } pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { let mut nonblocking = nonblocking as c_ulong; - let r = unsafe { c::ioctlsocket(self.0, c::FIONBIO as c_int, &mut nonblocking) }; - if r == 0 { Ok(()) } else { Err(io::Error::last_os_error()) } + let result = unsafe { c::ioctlsocket(self.0, c::FIONBIO as c_int, &mut nonblocking) }; + cvt(result).map(drop) } pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> { diff --git a/library/std/src/sys/windows/os.rs b/library/std/src/sys/windows/os.rs index 77c378a66af..8db97ba50a8 100644 --- a/library/std/src/sys/windows/os.rs +++ b/library/std/src/sys/windows/os.rs @@ -253,22 +253,13 @@ pub fn chdir(p: &path::Path) -> io::Result<()> { cvt(unsafe { c::SetCurrentDirectoryW(p.as_ptr()) }).map(drop) } -pub fn getenv(k: &OsStr) -> io::Result<Option<OsString>> { - let k = to_u16s(k)?; - let res = super::fill_utf16_buf( +pub fn getenv(k: &OsStr) -> Option<OsString> { + let k = to_u16s(k).ok()?; + super::fill_utf16_buf( |buf, sz| unsafe { c::GetEnvironmentVariableW(k.as_ptr(), buf, sz) }, |buf| OsStringExt::from_wide(buf), - ); - match res { - Ok(value) => Ok(Some(value)), - Err(e) => { - if e.raw_os_error() == Some(c::ERROR_ENVVAR_NOT_FOUND as i32) { - Ok(None) - } else { - Err(e) - } - } - } + ) + .ok() } pub fn setenv(k: &OsStr, v: &OsStr) -> io::Result<()> { diff --git a/library/std/src/sys/windows/process.rs b/library/std/src/sys/windows/process.rs index 81dbea4a067..ae193b82e91 100644 --- a/library/std/src/sys/windows/process.rs +++ b/library/std/src/sys/windows/process.rs @@ -3,7 +3,7 @@ #[cfg(test)] mod tests; -use crate::borrow::Borrow; +use crate::cmp; use crate::collections::BTreeMap; use crate::convert::{TryFrom, TryInto}; use crate::env; @@ -34,32 +34,115 @@ use libc::{c_void, EXIT_FAILURE, EXIT_SUCCESS}; // Command //////////////////////////////////////////////////////////////////////////////// -#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd)] +#[derive(Clone, Debug, Eq)] #[doc(hidden)] -pub struct EnvKey(OsString); +pub struct EnvKey { + os_string: OsString, + // This stores a UTF-16 encoded string to workaround the mismatch between + // Rust's OsString (WTF-8) and the Windows API string type (UTF-16). + // Normally converting on every API call is acceptable but here + // `c::CompareStringOrdinal` will be called for every use of `==`. + utf16: Vec<u16>, +} + +impl EnvKey { + fn new<T: Into<OsString>>(key: T) -> Self { + EnvKey::from(key.into()) + } +} + +// Comparing Windows environment variable keys[1] are behaviourally the +// composition of two operations[2]: +// +// 1. Case-fold both strings. This is done using a language-independent +// uppercase mapping that's unique to Windows (albeit based on data from an +// older Unicode spec). It only operates on individual UTF-16 code units so +// surrogates are left unchanged. This uppercase mapping can potentially change +// between Windows versions. +// +// 2. Perform an ordinal comparison of the strings. A comparison using ordinal +// is just a comparison based on the numerical value of each UTF-16 code unit[3]. +// +// Because the case-folding mapping is unique to Windows and not guaranteed to +// be stable, we ask the OS to compare the strings for us. This is done by +// calling `CompareStringOrdinal`[4] with `bIgnoreCase` set to `TRUE`. +// +// [1] https://docs.microsoft.com/en-us/dotnet/standard/base-types/best-practices-strings#choosing-a-stringcomparison-member-for-your-method-call +// [2] https://docs.microsoft.com/en-us/dotnet/standard/base-types/best-practices-strings#stringtoupper-and-stringtolower +// [3] https://docs.microsoft.com/en-us/dotnet/api/system.stringcomparison?view=net-5.0#System_StringComparison_Ordinal +// [4] https://docs.microsoft.com/en-us/windows/win32/api/stringapiset/nf-stringapiset-comparestringordinal +impl Ord for EnvKey { + fn cmp(&self, other: &Self) -> cmp::Ordering { + unsafe { + let result = c::CompareStringOrdinal( + self.utf16.as_ptr(), + self.utf16.len() as _, + other.utf16.as_ptr(), + other.utf16.len() as _, + c::TRUE, + ); + match result { + c::CSTR_LESS_THAN => cmp::Ordering::Less, + c::CSTR_EQUAL => cmp::Ordering::Equal, + c::CSTR_GREATER_THAN => cmp::Ordering::Greater, + // `CompareStringOrdinal` should never fail so long as the parameters are correct. + _ => panic!("comparing environment keys failed: {}", Error::last_os_error()), + } + } + } +} +impl PartialOrd for EnvKey { + fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> { + Some(self.cmp(other)) + } +} +impl PartialEq for EnvKey { + fn eq(&self, other: &Self) -> bool { + if self.utf16.len() != other.utf16.len() { + false + } else { + self.cmp(other) == cmp::Ordering::Equal + } + } +} +impl PartialOrd<str> for EnvKey { + fn partial_cmp(&self, other: &str) -> Option<cmp::Ordering> { + Some(self.cmp(&EnvKey::new(other))) + } +} +impl PartialEq<str> for EnvKey { + fn eq(&self, other: &str) -> bool { + if self.os_string.len() != other.len() { + false + } else { + self.cmp(&EnvKey::new(other)) == cmp::Ordering::Equal + } + } +} +// Environment variable keys should preserve their original case even though +// they are compared using a caseless string mapping. impl From<OsString> for EnvKey { - fn from(mut k: OsString) -> Self { - k.make_ascii_uppercase(); - EnvKey(k) + fn from(k: OsString) -> Self { + EnvKey { utf16: k.encode_wide().collect(), os_string: k } } } impl From<EnvKey> for OsString { fn from(k: EnvKey) -> Self { - k.0 + k.os_string } } -impl Borrow<OsStr> for EnvKey { - fn borrow(&self) -> &OsStr { - &self.0 +impl From<&OsStr> for EnvKey { + fn from(k: &OsStr) -> Self { + Self::from(k.to_os_string()) } } impl AsRef<OsStr> for EnvKey { fn as_ref(&self) -> &OsStr { - &self.0 + &self.os_string } } @@ -73,7 +156,7 @@ fn ensure_no_nuls<T: AsRef<OsStr>>(str: T) -> io::Result<T> { pub struct Command { program: OsString, - args: Vec<OsString>, + args: Vec<Arg>, env: CommandEnv, cwd: Option<OsString>, flags: u32, @@ -97,6 +180,14 @@ pub struct StdioPipes { pub stderr: Option<AnonPipe>, } +#[derive(Debug)] +enum Arg { + /// Add quotes (if needed) + Regular(OsString), + /// Append raw string without quoting + Raw(OsString), +} + impl Command { pub fn new(program: &OsStr) -> Command { Command { @@ -114,7 +205,7 @@ impl Command { } pub fn arg(&mut self, arg: &OsStr) { - self.args.push(arg.to_os_string()) + self.args.push(Arg::Regular(arg.to_os_string())) } pub fn env_mut(&mut self) -> &mut CommandEnv { &mut self.env @@ -139,6 +230,10 @@ impl Command { self.force_quotes_enabled = enabled; } + pub fn raw_arg(&mut self, command_str_to_append: &OsStr) { + self.args.push(Arg::Raw(command_str_to_append.to_os_string())) + } + pub fn get_program(&self) -> &OsStr { &self.program } @@ -166,7 +261,7 @@ impl Command { // to read the *child's* PATH if one is provided. See #15149 for more // details. let program = maybe_env.as_ref().and_then(|env| { - if let Some(v) = env.get(OsStr::new("PATH")) { + if let Some(v) = env.get(&EnvKey::new("PATH")) { // Split the value and test each path to see if the // program exists. for path in split_paths(&v) { @@ -207,7 +302,7 @@ impl Command { // the remaining portion of this spawn in a mutex. // // For more information, msdn also has an article about this race: - // http://support.microsoft.com/kb/315939 + // https://support.microsoft.com/kb/315939 static CREATE_PROCESS_LOCK: StaticMutex = StaticMutex::new(); let _guard = unsafe { CREATE_PROCESS_LOCK.lock() }; @@ -251,9 +346,13 @@ impl Command { impl fmt::Debug for Command { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:?}", self.program)?; + self.program.fmt(f)?; for arg in &self.args { - write!(f, " {:?}", arg)?; + f.write_str(" ")?; + match arg { + Arg::Regular(s) => s.fmt(f), + Arg::Raw(s) => f.write_str(&s.to_string_lossy()), + }?; } Ok(()) } @@ -472,44 +571,63 @@ fn zeroed_process_information() -> c::PROCESS_INFORMATION { } } +enum Quote { + // Every arg is quoted + Always, + // Whitespace and empty args are quoted + Auto, + // Arg appended without any changes (#29494) + Never, +} + // Produces a wide string *without terminating null*; returns an error if // `prog` or any of the `args` contain a nul. -fn make_command_line(prog: &OsStr, args: &[OsString], force_quotes: bool) -> io::Result<Vec<u16>> { +fn make_command_line(prog: &OsStr, args: &[Arg], force_quotes: bool) -> io::Result<Vec<u16>> { // Encode the command and arguments in a command line string such // that the spawned process may recover them using CommandLineToArgvW. let mut cmd: Vec<u16> = Vec::new(); // Always quote the program name so CreateProcess doesn't interpret args as // part of the name if the binary wasn't found first time. - append_arg(&mut cmd, prog, true)?; + append_arg(&mut cmd, prog, Quote::Always)?; for arg in args { cmd.push(' ' as u16); - append_arg(&mut cmd, arg, force_quotes)?; + let (arg, quote) = match arg { + Arg::Regular(arg) => (arg, if force_quotes { Quote::Always } else { Quote::Auto }), + Arg::Raw(arg) => (arg, Quote::Never), + }; + append_arg(&mut cmd, arg, quote)?; } return Ok(cmd); - fn append_arg(cmd: &mut Vec<u16>, arg: &OsStr, force_quotes: bool) -> io::Result<()> { + fn append_arg(cmd: &mut Vec<u16>, arg: &OsStr, quote: Quote) -> io::Result<()> { // If an argument has 0 characters then we need to quote it to ensure // that it actually gets passed through on the command line or otherwise // it will be dropped entirely when parsed on the other end. ensure_no_nuls(arg)?; let arg_bytes = &arg.as_inner().inner.as_inner(); - let quote = force_quotes - || arg_bytes.iter().any(|c| *c == b' ' || *c == b'\t') - || arg_bytes.is_empty(); + let (quote, escape) = match quote { + Quote::Always => (true, true), + Quote::Auto => { + (arg_bytes.iter().any(|c| *c == b' ' || *c == b'\t') || arg_bytes.is_empty(), true) + } + Quote::Never => (false, false), + }; if quote { cmd.push('"' as u16); } let mut backslashes: usize = 0; for x in arg.encode_wide() { - if x == '\\' as u16 { - backslashes += 1; - } else { - if x == '"' as u16 { - // Add n+1 backslashes to total 2n+1 before internal '"'. - cmd.extend((0..=backslashes).map(|_| '\\' as u16)); + if escape { + if x == '\\' as u16 { + backslashes += 1; + } else { + if x == '"' as u16 { + // Add n+1 backslashes to total 2n+1 before internal '"'. + cmd.extend((0..=backslashes).map(|_| '\\' as u16)); + } + backslashes = 0; } - backslashes = 0; } cmd.push(x); } @@ -530,8 +648,15 @@ fn make_envp(maybe_env: Option<BTreeMap<EnvKey, OsString>>) -> io::Result<(*mut if let Some(env) = maybe_env { let mut blk = Vec::new(); + // If there are no environment variables to set then signal this by + // pushing a null. + if env.is_empty() { + blk.push(0); + } + for (k, v) in env { - blk.extend(ensure_no_nuls(k.0)?.encode_wide()); + ensure_no_nuls(k.os_string)?; + blk.extend(k.utf16); blk.push('=' as u16); blk.extend(ensure_no_nuls(v)?.encode_wide()); blk.push(0); @@ -555,13 +680,15 @@ fn make_dirp(d: Option<&OsString>) -> io::Result<(*const u16, Vec<u16>)> { } pub struct CommandArgs<'a> { - iter: crate::slice::Iter<'a, OsString>, + iter: crate::slice::Iter<'a, Arg>, } impl<'a> Iterator for CommandArgs<'a> { type Item = &'a OsStr; fn next(&mut self) -> Option<&'a OsStr> { - self.iter.next().map(|s| s.as_ref()) + self.iter.next().map(|arg| match arg { + Arg::Regular(s) | Arg::Raw(s) => s.as_ref(), + }) } fn size_hint(&self) -> (usize, Option<usize>) { self.iter.size_hint() diff --git a/library/std/src/sys/windows/process/tests.rs b/library/std/src/sys/windows/process/tests.rs index 8830ae049c6..3b65856dcac 100644 --- a/library/std/src/sys/windows/process/tests.rs +++ b/library/std/src/sys/windows/process/tests.rs @@ -1,12 +1,35 @@ use super::make_command_line; +use super::Arg; +use crate::env; use crate::ffi::{OsStr, OsString}; +use crate::process::Command; + +#[test] +fn test_raw_args() { + let command_line = &make_command_line( + OsStr::new("quoted exe"), + &[ + Arg::Regular(OsString::from("quote me")), + Arg::Raw(OsString::from("quote me *not*")), + Arg::Raw(OsString::from("\t\\")), + Arg::Raw(OsString::from("internal \\\"backslash-\"quote")), + Arg::Regular(OsString::from("optional-quotes")), + ], + false, + ) + .unwrap(); + assert_eq!( + String::from_utf16(command_line).unwrap(), + "\"quoted exe\" \"quote me\" quote me *not* \t\\ internal \\\"backslash-\"quote optional-quotes" + ); +} #[test] fn test_make_command_line() { fn test_wrapper(prog: &str, args: &[&str], force_quotes: bool) -> String { let command_line = &make_command_line( OsStr::new(prog), - &args.iter().map(|a| OsString::from(a)).collect::<Vec<OsString>>(), + &args.iter().map(|a| Arg::Regular(OsString::from(a))).collect::<Vec<_>>(), force_quotes, ) .unwrap(); @@ -15,6 +38,11 @@ fn test_make_command_line() { assert_eq!(test_wrapper("prog", &["aaa", "bbb", "ccc"], false), "\"prog\" aaa bbb ccc"); + assert_eq!(test_wrapper("prog", &[r"C:\"], false), r#""prog" C:\"#); + assert_eq!(test_wrapper("prog", &[r"2slashes\\"], false), r#""prog" 2slashes\\"#); + assert_eq!(test_wrapper("prog", &[r" C:\"], false), r#""prog" " C:\\""#); + assert_eq!(test_wrapper("prog", &[r" 2slashes\\"], false), r#""prog" " 2slashes\\\\""#); + assert_eq!( test_wrapper("C:\\Program Files\\blah\\blah.exe", &["aaa"], false), "\"C:\\Program Files\\blah\\blah.exe\" aaa" @@ -41,3 +69,62 @@ fn test_make_command_line() { "\"\u{03c0}\u{042f}\u{97f3}\u{00e6}\u{221e}\"" ); } + +// On Windows, environment args are case preserving but comparisons are case-insensitive. +// See: #85242 +#[test] +fn windows_env_unicode_case() { + let test_cases = [ + ("ä", "Ä"), + ("ß", "SS"), + ("Ä", "Ö"), + ("Ä", "Ö"), + ("I", "İ"), + ("I", "i"), + ("I", "ı"), + ("i", "I"), + ("i", "İ"), + ("i", "ı"), + ("İ", "I"), + ("İ", "i"), + ("İ", "ı"), + ("ı", "I"), + ("ı", "i"), + ("ı", "İ"), + ("ä", "Ä"), + ("ß", "SS"), + ("Ä", "Ö"), + ("Ä", "Ö"), + ("I", "İ"), + ("I", "i"), + ("I", "ı"), + ("i", "I"), + ("i", "İ"), + ("i", "ı"), + ("İ", "I"), + ("İ", "i"), + ("İ", "ı"), + ("ı", "I"), + ("ı", "i"), + ("ı", "İ"), + ]; + // Test that `cmd.env` matches `env::set_var` when setting two strings that + // may (or may not) be case-folded when compared. + for (a, b) in test_cases.iter() { + let mut cmd = Command::new("cmd"); + cmd.env(a, "1"); + cmd.env(b, "2"); + env::set_var(a, "1"); + env::set_var(b, "2"); + + for (key, value) in cmd.get_envs() { + assert_eq!( + env::var(key).ok(), + value.map(|s| s.to_string_lossy().into_owned()), + "command environment mismatch: {} {}", + a, + b + ); + } + } +} diff --git a/library/std/src/sys/windows/rwlock.rs b/library/std/src/sys/windows/rwlock.rs index a769326352c..b7a5b1e7acc 100644 --- a/library/std/src/sys/windows/rwlock.rs +++ b/library/std/src/sys/windows/rwlock.rs @@ -5,6 +5,8 @@ pub struct RWLock { inner: UnsafeCell<c::SRWLOCK>, } +pub type MovableRWLock = RWLock; + unsafe impl Send for RWLock {} unsafe impl Sync for RWLock {} diff --git a/library/std/src/sys/windows/stdio.rs b/library/std/src/sys/windows/stdio.rs index be3141e46a1..2973951fe90 100644 --- a/library/std/src/sys/windows/stdio.rs +++ b/library/std/src/sys/windows/stdio.rs @@ -169,7 +169,7 @@ impl io::Read for Stdin { // We assume that if the last `u16` is an unpaired surrogate they got sliced apart by our // buffer size, and keep it around for the next read hoping to put them together. -// This is a best effort, and may not work if we are not the only reader on Stdin. +// This is a best effort, and might not work if we are not the only reader on Stdin. fn read_u16s_fixup_surrogates( handle: c::HANDLE, buf: &mut [u16], diff --git a/library/std/src/sys/windows/thread.rs b/library/std/src/sys/windows/thread.rs index 38839ea5e90..ef7a9733fd8 100644 --- a/library/std/src/sys/windows/thread.rs +++ b/library/std/src/sys/windows/thread.rs @@ -1,5 +1,6 @@ use crate::ffi::CStr; use crate::io; +use crate::num::NonZeroUsize; use crate::ptr; use crate::sys::c; use crate::sys::handle::Handle; @@ -98,6 +99,21 @@ impl Thread { } } +pub fn available_concurrency() -> io::Result<NonZeroUsize> { + let res = unsafe { + let mut sysinfo: c::SYSTEM_INFO = crate::mem::zeroed(); + c::GetSystemInfo(&mut sysinfo); + sysinfo.dwNumberOfProcessors as usize + }; + match res { + 0 => Err(io::Error::new_const( + io::ErrorKind::NotFound, + &"The number of hardware threads is not known for the target platform", + )), + cpus => Ok(unsafe { NonZeroUsize::new_unchecked(cpus) }), + } +} + #[cfg_attr(test, allow(dead_code))] pub mod guard { pub type Guard = !; diff --git a/library/std/src/sys/windows/thread_local_key.rs b/library/std/src/sys/windows/thread_local_key.rs index 065365e5572..0bc51114665 100644 --- a/library/std/src/sys/windows/thread_local_key.rs +++ b/library/std/src/sys/windows/thread_local_key.rs @@ -35,7 +35,7 @@ pub type Dtor = unsafe extern "C" fn(*mut u8); // // For more details and nitty-gritty, see the code sections below! // -// [1]: http://www.codeproject.com/Articles/8113/Thread-Local-Storage-The-C-Way +// [1]: https://www.codeproject.com/Articles/8113/Thread-Local-Storage-The-C-Way // [2]: https://github.com/ChromiumWebApps/chromium/blob/master/base // /threading/thread_local_storage_win.cc#L42 diff --git a/library/std/src/sys_common/backtrace.rs b/library/std/src/sys_common/backtrace.rs index a549770d8b3..e6a099f0e81 100644 --- a/library/std/src/sys_common/backtrace.rs +++ b/library/std/src/sys_common/backtrace.rs @@ -75,7 +75,7 @@ unsafe fn _print_fmt(fmt: &mut fmt::Formatter<'_>, print_fmt: PrintFmt) -> fmt:: hit = true; if print_fmt == PrintFmt::Short { if let Some(sym) = symbol.name().and_then(|s| s.as_str()) { - if sym.contains("__rust_begin_short_backtrace") { + if start && sym.contains("__rust_begin_short_backtrace") { stop = true; return; } diff --git a/library/std/src/sys_common/bytestring.rs b/library/std/src/sys_common/bytestring.rs deleted file mode 100644 index 97fba60c271..00000000000 --- a/library/std/src/sys_common/bytestring.rs +++ /dev/null @@ -1,26 +0,0 @@ -#![allow(dead_code)] - -#[cfg(test)] -mod tests; - -use crate::fmt::{Formatter, Result, Write}; -use core::str::lossy::{Utf8Lossy, Utf8LossyChunk}; - -pub fn debug_fmt_bytestring(slice: &[u8], f: &mut Formatter<'_>) -> Result { - // Writes out a valid unicode string with the correct escape sequences - fn write_str_escaped(f: &mut Formatter<'_>, s: &str) -> Result { - for c in s.chars().flat_map(|c| c.escape_debug()) { - f.write_char(c)? - } - Ok(()) - } - - f.write_str("\"")?; - for Utf8LossyChunk { valid, broken } in Utf8Lossy::from_bytes(slice).chunks() { - write_str_escaped(f, valid)?; - for b in broken { - write!(f, "\\x{:02X}", b)?; - } - } - f.write_str("\"") -} diff --git a/library/std/src/sys_common/bytestring/tests.rs b/library/std/src/sys_common/bytestring/tests.rs deleted file mode 100644 index 1685f087d18..00000000000 --- a/library/std/src/sys_common/bytestring/tests.rs +++ /dev/null @@ -1,19 +0,0 @@ -use super::*; -use crate::fmt::{Debug, Formatter, Result}; - -#[test] -fn smoke() { - struct Helper<'a>(&'a [u8]); - - impl Debug for Helper<'_> { - fn fmt(&self, f: &mut Formatter<'_>) -> Result { - debug_fmt_bytestring(self.0, f) - } - } - - let input = b"\xF0hello,\tworld"; - let expected = r#""\xF0hello,\tworld""#; - let output = format!("{:?}", Helper(input)); - - assert!(output == expected); -} diff --git a/library/std/src/sys_common/io.rs b/library/std/src/sys_common/io.rs index 7c1d98a5abd..ea9108f1713 100644 --- a/library/std/src/sys_common/io.rs +++ b/library/std/src/sys_common/io.rs @@ -1,4 +1,6 @@ -pub const DEFAULT_BUF_SIZE: usize = 8 * 1024; +// Bare metal platforms usually have very small amounts of RAM +// (in the order of hundreds of KB) +pub const DEFAULT_BUF_SIZE: usize = if cfg!(target_os = "espidf") { 512 } else { 8 * 1024 }; #[cfg(test)] #[allow(dead_code)] // not used on emscripten diff --git a/library/std/src/sys_common/mod.rs b/library/std/src/sys_common/mod.rs index 1a9caa22c92..894440564b7 100644 --- a/library/std/src/sys_common/mod.rs +++ b/library/std/src/sys_common/mod.rs @@ -21,16 +21,11 @@ mod tests; pub mod backtrace; -pub mod bytestring; pub mod condvar; pub mod fs; pub mod io; pub mod memchr; pub mod mutex; -// `doc` is required because `sys/mod.rs` imports `unix/ext/mod.rs` on Windows -// when generating documentation. -#[cfg(any(doc, not(windows)))] -pub mod os_str_bytes; pub mod process; pub mod remutex; #[macro_use] diff --git a/library/std/src/sys_common/process.rs b/library/std/src/sys_common/process.rs index fe89b11043c..38007d5c414 100644 --- a/library/std/src/sys_common/process.rs +++ b/library/std/src/sys_common/process.rs @@ -65,16 +65,18 @@ impl CommandEnv { // The following functions build up changes pub fn set(&mut self, key: &OsStr, value: &OsStr) { + let key = EnvKey::from(key); self.maybe_saw_path(&key); - self.vars.insert(key.to_owned().into(), Some(value.to_owned())); + self.vars.insert(key, Some(value.to_owned())); } pub fn remove(&mut self, key: &OsStr) { + let key = EnvKey::from(key); self.maybe_saw_path(&key); if self.clear { - self.vars.remove(key); + self.vars.remove(&key); } else { - self.vars.insert(key.to_owned().into(), None); + self.vars.insert(key, None); } } @@ -87,7 +89,7 @@ impl CommandEnv { self.saw_path || self.clear } - fn maybe_saw_path(&mut self, key: &OsStr) { + fn maybe_saw_path(&mut self, key: &EnvKey) { if !self.saw_path && key == "PATH" { self.saw_path = true; } diff --git a/library/std/src/sys_common/rwlock.rs b/library/std/src/sys_common/rwlock.rs index 3705d641a1b..07ec20f4dc6 100644 --- a/library/std/src/sys_common/rwlock.rs +++ b/library/std/src/sys_common/rwlock.rs @@ -1,63 +1,112 @@ use crate::sys::rwlock as imp; +/// An OS-based reader-writer lock, meant for use in static variables. +/// +/// This rwlock does not implement poisoning. +/// +/// This rwlock has a const constructor ([`StaticRWLock::new`]), does not +/// implement `Drop` to cleanup resources. +pub struct StaticRWLock(imp::RWLock); + +impl StaticRWLock { + /// Creates a new rwlock for use. + pub const fn new() -> Self { + Self(imp::RWLock::new()) + } + + /// Acquires shared access to the underlying lock, blocking the current + /// thread to do so. + /// + /// The lock is automatically unlocked when the returned guard is dropped. + #[inline] + pub fn read(&'static self) -> StaticRWLockReadGuard { + unsafe { self.0.read() }; + StaticRWLockReadGuard(&self.0) + } + + /// Acquires write access to the underlying lock, blocking the current thread + /// to do so. + /// + /// The lock is automatically unlocked when the returned guard is dropped. + #[inline] + pub fn write(&'static self) -> StaticRWLockWriteGuard { + unsafe { self.0.write() }; + StaticRWLockWriteGuard(&self.0) + } +} + +#[must_use] +pub struct StaticRWLockReadGuard(&'static imp::RWLock); + +impl Drop for StaticRWLockReadGuard { + #[inline] + fn drop(&mut self) { + unsafe { + self.0.read_unlock(); + } + } +} + +#[must_use] +pub struct StaticRWLockWriteGuard(&'static imp::RWLock); + +impl Drop for StaticRWLockWriteGuard { + #[inline] + fn drop(&mut self) { + unsafe { + self.0.write_unlock(); + } + } +} + /// An OS-based reader-writer lock. /// -/// This structure is entirely unsafe and serves as the lowest layer of a -/// cross-platform binding of system rwlocks. It is recommended to use the -/// safer types at the top level of this crate instead of this type. -pub struct RWLock(imp::RWLock); +/// This rwlock does *not* have a const constructor, cleans up its resources in +/// its `Drop` implementation and may safely be moved (when not borrowed). +/// +/// This rwlock does not implement poisoning. +/// +/// This is either a wrapper around `Box<imp::RWLock>` or `imp::RWLock`, +/// depending on the platform. It is boxed on platforms where `imp::RWLock` may +/// not be moved. +pub struct MovableRWLock(imp::MovableRWLock); -impl RWLock { +impl MovableRWLock { /// Creates a new reader-writer lock for use. - /// - /// Behavior is undefined if the reader-writer lock is moved after it is - /// first used with any of the functions below. - pub const fn new() -> RWLock { - RWLock(imp::RWLock::new()) + pub fn new() -> Self { + Self(imp::MovableRWLock::from(imp::RWLock::new())) } /// Acquires shared access to the underlying lock, blocking the current /// thread to do so. - /// - /// Behavior is undefined if the rwlock has been moved between this and any - /// previous method call. #[inline] - pub unsafe fn read(&self) { - self.0.read() + pub fn read(&self) { + unsafe { self.0.read() } } /// Attempts to acquire shared access to this lock, returning whether it /// succeeded or not. /// /// This function does not block the current thread. - /// - /// Behavior is undefined if the rwlock has been moved between this and any - /// previous method call. #[inline] - pub unsafe fn try_read(&self) -> bool { - self.0.try_read() + pub fn try_read(&self) -> bool { + unsafe { self.0.try_read() } } /// Acquires write access to the underlying lock, blocking the current thread /// to do so. - /// - /// Behavior is undefined if the rwlock has been moved between this and any - /// previous method call. #[inline] - pub unsafe fn write(&self) { - self.0.write() + pub fn write(&self) { + unsafe { self.0.write() } } /// Attempts to acquire exclusive access to this lock, returning whether it /// succeeded or not. /// /// This function does not block the current thread. - /// - /// Behavior is undefined if the rwlock has been moved between this and any - /// previous method call. #[inline] - pub unsafe fn try_write(&self) -> bool { - self.0.try_write() + pub fn try_write(&self) -> bool { + unsafe { self.0.try_write() } } /// Unlocks previously acquired shared access to this lock. @@ -76,13 +125,10 @@ impl RWLock { pub unsafe fn write_unlock(&self) { self.0.write_unlock() } +} - /// Destroys OS-related resources with this RWLock. - /// - /// Behavior is undefined if there are any currently active users of this - /// lock. - #[inline] - pub unsafe fn destroy(&self) { - self.0.destroy() +impl Drop for MovableRWLock { + fn drop(&mut self) { + unsafe { self.0.destroy() }; } } diff --git a/library/std/src/sys_common/wtf8.rs b/library/std/src/sys_common/wtf8.rs index 7d4b0d52831..1bd3cfd2200 100644 --- a/library/std/src/sys_common/wtf8.rs +++ b/library/std/src/sys_common/wtf8.rs @@ -853,10 +853,11 @@ impl<'a> Iterator for EncodeWide<'a> { #[inline] fn size_hint(&self) -> (usize, Option<usize>) { let (low, high) = self.code_points.size_hint(); + let ext = (self.extra != 0) as usize; // every code point gets either one u16 or two u16, // so this iterator is between 1 or 2 times as // long as the underlying iterator. - (low, high.and_then(|n| n.checked_mul(2))) + (low + ext, high.and_then(|n| n.checked_mul(2)).and_then(|n| n.checked_add(ext))) } } diff --git a/library/std/src/sys_common/wtf8/tests.rs b/library/std/src/sys_common/wtf8/tests.rs index 385e01f92fa..1bafbaa6939 100644 --- a/library/std/src/sys_common/wtf8/tests.rs +++ b/library/std/src/sys_common/wtf8/tests.rs @@ -301,7 +301,7 @@ fn wtf8_slice() { #[test] #[should_panic] fn wtf8_slice_not_code_point_boundary() { - &Wtf8::from_str("aé 💩")[2..4]; + let _ = &Wtf8::from_str("aé 💩")[2..4]; } #[test] @@ -312,7 +312,7 @@ fn wtf8_slice_from() { #[test] #[should_panic] fn wtf8_slice_from_not_code_point_boundary() { - &Wtf8::from_str("aé 💩")[2..]; + let _ = &Wtf8::from_str("aé 💩")[2..]; } #[test] @@ -323,7 +323,7 @@ fn wtf8_slice_to() { #[test] #[should_panic] fn wtf8_slice_to_not_code_point_boundary() { - &Wtf8::from_str("aé 💩")[5..]; + let _ = &Wtf8::from_str("aé 💩")[5..]; } #[test] @@ -395,3 +395,15 @@ fn wtf8_encode_wide() { vec![0x61, 0xE9, 0x20, 0xD83D, 0xD83D, 0xDCA9] ); } + +#[test] +fn wtf8_encode_wide_size_hint() { + let string = Wtf8Buf::from_str("\u{12345}"); + let mut iter = string.encode_wide(); + assert_eq!((1, Some(8)), iter.size_hint()); + iter.next().unwrap(); + assert_eq!((1, Some(1)), iter.size_hint()); + iter.next().unwrap(); + assert_eq!((0, Some(0)), iter.size_hint()); + assert!(iter.next().is_none()); +} diff --git a/library/std/src/thread/available_concurrency.rs b/library/std/src/thread/available_concurrency.rs deleted file mode 100644 index e8cdde88014..00000000000 --- a/library/std/src/thread/available_concurrency.rs +++ /dev/null @@ -1,156 +0,0 @@ -use crate::io; -use crate::num::NonZeroUsize; - -/// Returns the number of hardware threads available to the program. -/// -/// This value should be considered only a hint. -/// -/// # Platform-specific behavior -/// -/// If interpreted as the number of actual hardware threads, it may undercount on -/// Windows systems with more than 64 hardware threads. If interpreted as the -/// available concurrency for that process, it may overcount on Windows systems -/// when limited by a process wide affinity mask or job object limitations, and -/// it may overcount on Linux systems when limited by a process wide affinity -/// mask or affected by cgroups limits. -/// -/// # Errors -/// -/// This function will return an error in the following situations, but is not -/// limited to just these cases: -/// -/// - If the number of hardware threads is not known for the target platform. -/// - The process lacks permissions to view the number of hardware threads -/// available. -/// -/// # Examples -/// -/// ``` -/// # #![allow(dead_code)] -/// #![feature(available_concurrency)] -/// use std::thread; -/// -/// let count = thread::available_concurrency().map(|n| n.get()).unwrap_or(1); -/// ``` -#[unstable(feature = "available_concurrency", issue = "74479")] -pub fn available_concurrency() -> io::Result<NonZeroUsize> { - available_concurrency_internal() -} - -cfg_if::cfg_if! { - if #[cfg(windows)] { - #[allow(nonstandard_style)] - fn available_concurrency_internal() -> io::Result<NonZeroUsize> { - #[repr(C)] - struct SYSTEM_INFO { - wProcessorArchitecture: u16, - wReserved: u16, - dwPageSize: u32, - lpMinimumApplicationAddress: *mut u8, - lpMaximumApplicationAddress: *mut u8, - dwActiveProcessorMask: *mut u8, - dwNumberOfProcessors: u32, - dwProcessorType: u32, - dwAllocationGranularity: u32, - wProcessorLevel: u16, - wProcessorRevision: u16, - } - extern "system" { - fn GetSystemInfo(info: *mut SYSTEM_INFO) -> i32; - } - let res = unsafe { - let mut sysinfo = crate::mem::zeroed(); - GetSystemInfo(&mut sysinfo); - sysinfo.dwNumberOfProcessors as usize - }; - match res { - 0 => Err(io::Error::new_const(io::ErrorKind::NotFound, &"The number of hardware threads is not known for the target platform")), - cpus => Ok(unsafe { NonZeroUsize::new_unchecked(cpus) }), - } - } - } else if #[cfg(any( - target_os = "android", - target_os = "emscripten", - target_os = "fuchsia", - target_os = "ios", - target_os = "linux", - target_os = "macos", - target_os = "solaris", - target_os = "illumos", - ))] { - fn available_concurrency_internal() -> io::Result<NonZeroUsize> { - match unsafe { libc::sysconf(libc::_SC_NPROCESSORS_ONLN) } { - -1 => Err(io::Error::last_os_error()), - 0 => Err(io::Error::new_const(io::ErrorKind::NotFound, &"The number of hardware threads is not known for the target platform")), - cpus => Ok(unsafe { NonZeroUsize::new_unchecked(cpus as usize) }), - } - } - } else if #[cfg(any(target_os = "freebsd", target_os = "dragonfly", target_os = "netbsd"))] { - fn available_concurrency_internal() -> io::Result<NonZeroUsize> { - use crate::ptr; - - let mut cpus: libc::c_uint = 0; - let mut cpus_size = crate::mem::size_of_val(&cpus); - - unsafe { - cpus = libc::sysconf(libc::_SC_NPROCESSORS_ONLN) as libc::c_uint; - } - - // Fallback approach in case of errors or no hardware threads. - if cpus < 1 { - let mut mib = [libc::CTL_HW, libc::HW_NCPU, 0, 0]; - let res = unsafe { - libc::sysctl( - mib.as_mut_ptr(), - 2, - &mut cpus as *mut _ as *mut _, - &mut cpus_size as *mut _ as *mut _, - ptr::null_mut(), - 0, - ) - }; - - // Handle errors if any. - if res == -1 { - return Err(io::Error::last_os_error()); - } else if cpus == 0 { - return Err(io::Error::new_const(io::ErrorKind::NotFound, &"The number of hardware threads is not known for the target platform")); - } - } - Ok(unsafe { NonZeroUsize::new_unchecked(cpus as usize) }) - } - } else if #[cfg(target_os = "openbsd")] { - fn available_concurrency_internal() -> io::Result<NonZeroUsize> { - use crate::ptr; - - let mut cpus: libc::c_uint = 0; - let mut cpus_size = crate::mem::size_of_val(&cpus); - let mut mib = [libc::CTL_HW, libc::HW_NCPU, 0, 0]; - - let res = unsafe { - libc::sysctl( - mib.as_mut_ptr(), - 2, - &mut cpus as *mut _ as *mut _, - &mut cpus_size as *mut _ as *mut _, - ptr::null_mut(), - 0, - ) - }; - - // Handle errors if any. - if res == -1 { - return Err(io::Error::last_os_error()); - } else if cpus == 0 { - return Err(io::Error::new_const(io::ErrorKind::NotFound, &"The number of hardware threads is not known for the target platform")); - } - - Ok(unsafe { NonZeroUsize::new_unchecked(cpus as usize) }) - } - } else { - // FIXME: implement on vxWorks, Redox, HermitCore, Haiku, l4re - fn available_concurrency_internal() -> io::Result<NonZeroUsize> { - Err(io::Error::new_const(io::ErrorKind::NotFound, &"The number of hardware threads is not known for the target platform")) - } - } -} diff --git a/library/std/src/thread/local.rs b/library/std/src/thread/local.rs index e62f4440b36..c53290ec0c7 100644 --- a/library/std/src/thread/local.rs +++ b/library/std/src/thread/local.rs @@ -324,10 +324,9 @@ macro_rules! __thread_local_inner { /// An error returned by [`LocalKey::try_with`](struct.LocalKey.html#method.try_with). #[stable(feature = "thread_local_try_with", since = "1.26.0")] +#[non_exhaustive] #[derive(Clone, Copy, Eq, PartialEq)] -pub struct AccessError { - _private: (), -} +pub struct AccessError; #[stable(feature = "thread_local_try_with", since = "1.26.0")] impl fmt::Debug for AccessError { @@ -396,7 +395,7 @@ impl<T: 'static> LocalKey<T> { F: FnOnce(&T) -> R, { unsafe { - let thread_local = (self.inner)().ok_or(AccessError { _private: () })?; + let thread_local = (self.inner)().ok_or(AccessError)?; Ok(f(thread_local)) } } diff --git a/library/std/src/thread/local/tests.rs b/library/std/src/thread/local/tests.rs index f33d6129619..1df1ca758c0 100644 --- a/library/std/src/thread/local/tests.rs +++ b/library/std/src/thread/local/tests.rs @@ -297,7 +297,7 @@ fn join_orders_after_tls_destructors() { .unwrap(); loop { - match SYNC_STATE.compare_exchange_weak( + match SYNC_STATE.compare_exchange( THREAD1_WAITING, MAIN_THREAD_RENDEZVOUS, Ordering::SeqCst, diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs index 30d8c2a1b6f..f44df845bf4 100644 --- a/library/std/src/thread/mod.rs +++ b/library/std/src/thread/mod.rs @@ -28,7 +28,7 @@ //! When the main thread of a Rust program terminates, the entire program shuts //! down, even if other threads are still running. However, this module provides //! convenient facilities for automatically waiting for the termination of a -//! child thread (i.e., join). +//! thread (i.e., join). //! //! ## Spawning a thread //! @@ -42,38 +42,43 @@ //! }); //! ``` //! -//! In this example, the spawned thread is "detached" from the current -//! thread. This means that it can outlive its parent (the thread that spawned -//! it), unless this parent is the main thread. +//! In this example, the spawned thread is "detached," which means that there is +//! no way for the program to learn when the spawned thread completes or otherwise +//! terminates. //! -//! The parent thread can also wait on the completion of the child -//! thread; a call to [`spawn`] produces a [`JoinHandle`], which provides -//! a `join` method for waiting: +//! To learn when a thread completes, it is necessary to capture the [`JoinHandle`] +//! object that is returned by the call to [`spawn`], which provides +//! a `join` method that allows the caller to wait for the completion of the +//! spawned thread: //! //! ```rust //! use std::thread; //! -//! let child = thread::spawn(move || { +//! let thread_join_handle = thread::spawn(move || { //! // some work here //! }); //! // some work here -//! let res = child.join(); +//! let res = thread_join_handle.join(); //! ``` //! //! The [`join`] method returns a [`thread::Result`] containing [`Ok`] of the final -//! value produced by the child thread, or [`Err`] of the value given to -//! a call to [`panic!`] if the child panicked. +//! value produced by the spawned thread, or [`Err`] of the value given to +//! a call to [`panic!`] if the thread panicked. +//! +//! Note that there is no parent/child relationship between a thread that spawns a +//! new thread and the thread being spawned. In particular, the spawned thread may or +//! may not outlive the spawning thread, unless the spawning thread is the main thread. //! //! ## Configuring threads //! //! A new thread can be configured before it is spawned via the [`Builder`] type, -//! which currently allows you to set the name and stack size for the child thread: +//! which currently allows you to set the name and stack size for the thread: //! //! ```rust //! # #![allow(unused_must_use)] //! use std::thread; //! -//! thread::Builder::new().name("child1".to_string()).spawn(move || { +//! thread::Builder::new().name("thread1".to_string()).spawn(move || { //! println!("Hello, world!"); //! }); //! ``` @@ -155,6 +160,7 @@ use crate::fmt; use crate::io; use crate::mem; use crate::num::NonZeroU64; +use crate::num::NonZeroUsize; use crate::panic; use crate::panicking; use crate::str; @@ -174,15 +180,9 @@ use crate::time::Duration; #[macro_use] mod local; -#[unstable(feature = "available_concurrency", issue = "74479")] -mod available_concurrency; - #[stable(feature = "rust1", since = "1.0.0")] pub use self::local::{AccessError, LocalKey}; -#[unstable(feature = "available_concurrency", issue = "74479")] -pub use available_concurrency::available_concurrency; - // The types used by the thread_local! macro to access TLS keys. Note that there // are two types, the "OS" type and the "fast" type. The OS thread local key // type is accessed via platform-specific API calls and is slow, while the fast @@ -349,7 +349,7 @@ impl Builder { /// The spawned thread may outlive the caller (unless the caller thread /// is the main thread; the whole process is terminated when the main /// thread finishes). The join handle can be used to block on - /// termination of the child thread, including recovering its panics. + /// termination of the spawned thread, including recovering its panics. /// /// For a more complete documentation see [`thread::spawn`][`spawn`]. /// @@ -394,7 +394,7 @@ impl Builder { /// The spawned thread may outlive the caller (unless the caller thread /// is the main thread; the whole process is terminated when the main /// thread finishes). The join handle can be used to block on - /// termination of the child thread, including recovering its panics. + /// termination of the spawned thread, including recovering its panics. /// /// This method is identical to [`thread::Builder::spawn`][`Builder::spawn`], /// except for the relaxed lifetime bounds, which render it unsafe. @@ -521,15 +521,16 @@ impl Builder { /// Spawns a new thread, returning a [`JoinHandle`] for it. /// -/// The join handle will implicitly *detach* the child thread upon being -/// dropped. In this case, the child thread may outlive the parent (unless -/// the parent thread is the main thread; the whole process is terminated when -/// the main thread finishes). Additionally, the join handle provides a [`join`] -/// method that can be used to join the child thread. If the child thread -/// panics, [`join`] will return an [`Err`] containing the argument given to -/// [`panic!`]. +/// 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 argument given to [`panic!`]. +/// +/// If the join handle is dropped, the spawned thread will implicitly be *detached*. +/// In this case, the spawned thread may no longer be joined. +/// (It is the responsibility of the program to either eventually join threads it +/// creates or detach them; otherwise, a resource leak will result.) /// -/// This will create a thread using default parameters of [`Builder`], if you +/// This call will create a thread using default parameters of [`Builder`], if you /// want to specify the stack size or the name of the thread, use this API /// instead. /// @@ -538,8 +539,8 @@ impl Builder { /// /// - The `'static` constraint means that the closure and its return value /// must have a lifetime of the whole program execution. The reason for this -/// is that threads can `detach` and outlive the lifetime they have been -/// created in. +/// is that threads can outlive the lifetime they have been created in. +/// /// Indeed if the thread, and by extension its return value, can outlive their /// caller, we need to make sure that they will be valid afterwards, and since /// we *can't* know when it will return we need to have them valid as long as @@ -656,22 +657,23 @@ pub fn current() -> Thread { /// Cooperatively gives up a timeslice to the OS scheduler. /// -/// This is used when the programmer knows that the thread will have nothing -/// to do for some time, and thus avoid wasting computing time. +/// This calls the underlying OS scheduler's yield primitive, signaling +/// that the calling thread is willing to give up its remaining timeslice +/// so that the OS may schedule other threads on the CPU. /// -/// For example when polling on a resource, it is common to check that it is -/// available, and if not to yield in order to avoid busy waiting. +/// A drawback of yielding in a loop is that if the OS does not have any +/// other ready threads to run on the current CPU, the thread will effectively +/// busy-wait, which wastes CPU time and energy. /// -/// Thus the pattern of `yield`ing after a failed poll is rather common when -/// implementing low-level shared resources or synchronization primitives. +/// Therefore, when waiting for events of interest, a programmer's first +/// choice should be to use synchronization devices such as [`channel`]s, +/// [`Condvar`]s, [`Mutex`]es or [`join`] since these primitives are +/// implemented in a blocking manner, giving up the CPU until the event +/// of interest has occurred which avoids repeated yielding. /// -/// However programmers will usually prefer to use [`channel`]s, [`Condvar`]s, -/// [`Mutex`]es or [`join`] for their synchronization routines, as they avoid -/// thinking about thread scheduling. -/// -/// Note that [`channel`]s for example are implemented using this primitive. -/// Indeed when you call `send` or `recv`, which are blocking, they will yield -/// if the channel is not available. +/// `yield_now` should thus be used only rarely, mostly in situations where +/// repeated polling is required because there is no other suitable way to +/// learn when an event of interest has occurred. /// /// # Examples /// @@ -910,7 +912,7 @@ pub fn park() { /// The semantics of this function are equivalent to [`park`] except /// that the thread will be blocked for roughly no longer than `dur`. This /// method should not be used for precise timing due to anomalies such as -/// preemption or platform differences that may not cause the maximum +/// preemption or platform differences that might not cause the maximum /// amount of time waited to be precisely `ms` long. /// /// See the [park documentation][`park`] for more detail. @@ -926,7 +928,7 @@ pub fn park_timeout_ms(ms: u32) { /// The semantics of this function are equivalent to [`park`][park] except /// that the thread will be blocked for roughly no longer than `dur`. This /// method should not be used for precise timing due to anomalies such as -/// preemption or platform differences that may not cause the maximum +/// preemption or platform differences that might not cause the maximum /// amount of time waited to be precisely `dur` long. /// /// See the [park documentation][park] for more details. @@ -1003,11 +1005,12 @@ impl ThreadId { static mut COUNTER: u64 = 1; unsafe { - let _guard = GUARD.lock(); + let guard = GUARD.lock(); // If we somehow use up all our bits, panic so that we're not // covering up subtle bugs of IDs being reused. if COUNTER == u64::MAX { + drop(guard); // in case the panic handler ends up calling `ThreadId::new()`, avoid reentrant lock acquire. panic!("failed to generate unique thread ID: bitspace exhausted"); } @@ -1239,10 +1242,10 @@ impl fmt::Debug for Thread { #[stable(feature = "rust1", since = "1.0.0")] pub type Result<T> = crate::result::Result<T, Box<dyn Any + Send + 'static>>; -// This packet is used to communicate the return value between the child thread -// and the parent thread. Memory is shared through the `Arc` within and there's +// This packet is used to communicate the return value between the spawned thread +// and the rest of the program. Memory is shared through the `Arc` within and there's // no need for a mutex here because synchronization happens with `join()` (the -// parent thread never reads this packet until the child has exited). +// caller will never read this packet until the thread has exited). // // This packet itself is then stored into a `JoinInner` which in turns is placed // in `JoinHandle` and `JoinGuard`. Due to the usage of `UnsafeCell` we need to @@ -1306,7 +1309,7 @@ impl<T> JoinInner<T> { /// }).unwrap(); /// ``` /// -/// Child being detached and outliving its parent: +/// A thread being detached and outliving the thread that spawned it: /// /// ```no_run /// use std::thread; @@ -1364,12 +1367,15 @@ impl<T> JoinHandle<T> { /// Waits for the associated thread to finish. /// + /// This function will return immediately if the associated thread has already finished. + /// /// 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 are ordered before 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 child thread panics, [`Err`] is returned with the parameter given + /// If the associated thread panics, [`Err`] is returned with the parameter given /// to [`panic!`]. /// /// [`Err`]: crate::result::Result::Err @@ -1422,3 +1428,39 @@ fn _assert_sync_and_send() { _assert_both::<JoinHandle<()>>(); _assert_both::<Thread>(); } + +/// Returns the number of hardware threads available to the program. +/// +/// This value should be considered only a hint. +/// +/// # Platform-specific behavior +/// +/// If interpreted as the number of actual hardware threads, it may undercount on +/// Windows systems with more than 64 hardware threads. If interpreted as the +/// available concurrency for that process, it may overcount on Windows systems +/// when limited by a process wide affinity mask or job object limitations, and +/// it may overcount on Linux systems when limited by a process wide affinity +/// mask or affected by cgroups limits. +/// +/// # Errors +/// +/// This function will return an error in the following situations, but is not +/// limited to just these cases: +/// +/// - If the number of hardware threads is not known for the target platform. +/// - The process lacks permissions to view the number of hardware threads +/// available. +/// +/// # Examples +/// +/// ``` +/// # #![allow(dead_code)] +/// #![feature(available_concurrency)] +/// use std::thread; +/// +/// let count = thread::available_concurrency().map(|n| n.get()).unwrap_or(1); +/// ``` +#[unstable(feature = "available_concurrency", issue = "74479")] +pub fn available_concurrency() -> io::Result<NonZeroUsize> { + imp::available_concurrency() +} diff --git a/library/std/src/time.rs b/library/std/src/time.rs index 899cf6841ee..6d70c7270d3 100644 --- a/library/std/src/time.rs +++ b/library/std/src/time.rs @@ -34,7 +34,7 @@ pub use core::time::Duration; /// benchmarks or timing how long an operation takes. /// /// Note, however, that instants are not guaranteed to be **steady**. In other -/// words, each tick of the underlying clock may not be the same length (e.g. +/// words, each tick of the underlying clock might not be the same length (e.g. /// some seconds may be longer than others). An instant may jump forwards or /// experience time dilation (slow down or speed up), but it will never go /// backwards. @@ -168,7 +168,7 @@ pub struct Instant(time::Instant); /// /// [`insecure_time` usercall]: https://edp.fortanix.com/docs/api/fortanix_sgx_abi/struct.Usercalls.html#method.insecure_time /// [timekeeping in SGX]: https://edp.fortanix.com/docs/concepts/rust-std/#codestdtimecode -/// [gettimeofday]: http://man7.org/linux/man-pages/man2/gettimeofday.2.html +/// [gettimeofday]: https://man7.org/linux/man-pages/man2/gettimeofday.2.html /// [clock_gettime (Realtime Clock)]: https://linux.die.net/man/3/clock_gettime /// [__wasi_clock_time_get (Realtime Clock)]: https://github.com/WebAssembly/WASI/blob/master/phases/snapshot/docs.md#clock_time_get /// [GetSystemTimePreciseAsFileTime]: https://docs.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-getsystemtimepreciseasfiletime @@ -485,7 +485,7 @@ impl SystemTime { /// /// This function may fail as the underlying system clock is susceptible to /// drift and updates (e.g., the system clock could go backwards), so this - /// function may not always succeed. If successful, [`Ok`]`(`[`Duration`]`)` is + /// function might not always succeed. If successful, [`Ok`]`(`[`Duration`]`)` is /// returned where the duration represents the amount of time elapsed from /// this time measurement to the current time. /// diff --git a/library/std/tests/run-time-detect.rs b/library/std/tests/run-time-detect.rs index c7107b5d0a3..079f00a5753 100644 --- a/library/std/tests/run-time-detect.rs +++ b/library/std/tests/run-time-detect.rs @@ -16,22 +16,56 @@ fn arm_linux() { println!("neon: {}", is_arm_feature_detected!("neon")); println!("pmull: {}", is_arm_feature_detected!("pmull")); + println!("crypto: {}", is_arm_feature_detected!("crypto")); + println!("crc: {}", is_arm_feature_detected!("crc")); + println!("aes: {}", is_arm_feature_detected!("aes")); + println!("sha2: {}", is_arm_feature_detected!("sha2")); } #[test] #[cfg(all(target_arch = "aarch64", any(target_os = "linux", target_os = "android")))] fn aarch64_linux() { - println!("fp: {}", is_aarch64_feature_detected!("fp")); - println!("fp16: {}", is_aarch64_feature_detected!("fp16")); println!("neon: {}", is_aarch64_feature_detected!("neon")); println!("asimd: {}", is_aarch64_feature_detected!("asimd")); + println!("pmull: {}", is_aarch64_feature_detected!("pmull")); + println!("fp: {}", is_aarch64_feature_detected!("fp")); + println!("fp16: {}", is_aarch64_feature_detected!("fp16")); println!("sve: {}", is_aarch64_feature_detected!("sve")); println!("crc: {}", is_aarch64_feature_detected!("crc")); println!("lse: {}", is_aarch64_feature_detected!("lse")); + println!("lse2: {}", is_aarch64_feature_detected!("lse2")); println!("rdm: {}", is_aarch64_feature_detected!("rdm")); println!("rcpc: {}", is_aarch64_feature_detected!("rcpc")); + println!("rcpc2: {}", is_aarch64_feature_detected!("rcpc2")); println!("dotprod: {}", is_aarch64_feature_detected!("dotprod")); println!("tme: {}", is_aarch64_feature_detected!("tme")); + println!("fhm: {}", is_aarch64_feature_detected!("fhm")); + println!("dit: {}", is_aarch64_feature_detected!("dit")); + println!("flagm: {}", is_aarch64_feature_detected!("flagm")); + println!("ssbs: {}", is_aarch64_feature_detected!("ssbs")); + println!("sb: {}", is_aarch64_feature_detected!("sb")); + println!("pauth: {}", is_aarch64_feature_detected!("pauth")); + println!("dpb: {}", is_aarch64_feature_detected!("dpb")); + println!("dpb2: {}", is_aarch64_feature_detected!("dpb2")); + println!("sve2: {}", is_aarch64_feature_detected!("sve2")); + println!("sve2-aes: {}", is_aarch64_feature_detected!("sve2-aes")); + println!("sve2-sm4: {}", is_aarch64_feature_detected!("sve2-sm4")); + println!("sve2-sha3: {}", is_aarch64_feature_detected!("sve2-sha3")); + println!("sve2-bitperm: {}", is_aarch64_feature_detected!("sve2-bitperm")); + println!("frintts: {}", is_aarch64_feature_detected!("frintts")); + println!("i8mm: {}", is_aarch64_feature_detected!("i8mm")); + println!("f32mm: {}", is_aarch64_feature_detected!("f32mm")); + println!("f64mm: {}", is_aarch64_feature_detected!("f64mm")); + println!("bf16: {}", is_aarch64_feature_detected!("bf16")); + println!("rand: {}", is_aarch64_feature_detected!("rand")); + println!("bti: {}", is_aarch64_feature_detected!("bti")); + println!("mte: {}", is_aarch64_feature_detected!("mte")); + println!("jsconv: {}", is_aarch64_feature_detected!("jsconv")); + println!("fcma: {}", is_aarch64_feature_detected!("fcma")); + println!("aes: {}", is_aarch64_feature_detected!("aes")); + println!("sha2: {}", is_aarch64_feature_detected!("sha2")); + println!("sha3: {}", is_aarch64_feature_detected!("sha3")); + println!("sm4: {}", is_aarch64_feature_detected!("sm4")); } #[test] diff --git a/library/stdarch b/library/stdarch -Subproject 37d6e1886369ea0176356286dc7fbd42ee5aa79 +Subproject c158cfd38e20d855f5d6ca8a5a101eefb82604a diff --git a/library/term/Cargo.toml b/library/term/Cargo.toml deleted file mode 100644 index ddf85b5c5bc..00000000000 --- a/library/term/Cargo.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -authors = ["The Rust Project Developers"] -name = "term" -version = "0.0.0" -edition = "2018" - -[dependencies] -core = { path = "../core" } -std = { path = "../std" } diff --git a/library/term/src/lib.rs b/library/term/src/lib.rs deleted file mode 100644 index 943b276a220..00000000000 --- a/library/term/src/lib.rs +++ /dev/null @@ -1,194 +0,0 @@ -//! Terminal formatting library. -//! -//! This crate provides the `Terminal` trait, which abstracts over an [ANSI -//! Terminal][ansi] to provide color printing, among other things. There are two -//! implementations, the `TerminfoTerminal`, which uses control characters from -//! a [terminfo][ti] database, and `WinConsole`, which uses the [Win32 Console -//! API][win]. -//! -//! # Examples -//! -//! ```no_run -//! # #![feature(rustc_private)] -//! extern crate term; -//! use std::io::prelude::*; -//! -//! fn main() { -//! let mut t = term::stdout().unwrap(); -//! -//! t.fg(term::color::GREEN).unwrap(); -//! write!(t, "hello, ").unwrap(); -//! -//! t.fg(term::color::RED).unwrap(); -//! writeln!(t, "world!").unwrap(); -//! -//! assert!(t.reset().unwrap()); -//! } -//! ``` -//! -//! [ansi]: https://en.wikipedia.org/wiki/ANSI_escape_code -//! [win]: https://docs.microsoft.com/en-us/windows/console/character-mode-applications -//! [ti]: https://en.wikipedia.org/wiki/Terminfo - -#![doc(html_playground_url = "https://play.rust-lang.org/", test(attr(deny(warnings))))] -#![deny(missing_docs)] -#![cfg_attr(windows, feature(libc))] - -use std::io::prelude::*; -use std::io::{self, Stderr, Stdout}; - -pub use terminfo::TerminfoTerminal; -#[cfg(windows)] -pub use win::WinConsole; - -pub mod terminfo; - -#[cfg(windows)] -mod win; - -/// Alias for stdout terminals. -pub type StdoutTerminal = dyn Terminal<Output = Stdout> + Send; -/// Alias for stderr terminals. -pub type StderrTerminal = dyn Terminal<Output = Stderr> + Send; - -#[cfg(not(windows))] -/// Returns a Terminal wrapping stdout, or None if a terminal couldn't be -/// opened. -pub fn stdout() -> Option<Box<StdoutTerminal>> { - TerminfoTerminal::new(io::stdout()).map(|t| Box::new(t) as Box<StdoutTerminal>) -} - -#[cfg(windows)] -/// Returns a Terminal wrapping stdout, or None if a terminal couldn't be -/// opened. -pub fn stdout() -> Option<Box<StdoutTerminal>> { - TerminfoTerminal::new(io::stdout()) - .map(|t| Box::new(t) as Box<StdoutTerminal>) - .or_else(|| WinConsole::new(io::stdout()).ok().map(|t| Box::new(t) as Box<StdoutTerminal>)) -} - -#[cfg(not(windows))] -/// Returns a Terminal wrapping stderr, or None if a terminal couldn't be -/// opened. -pub fn stderr() -> Option<Box<StderrTerminal>> { - TerminfoTerminal::new(io::stderr()).map(|t| Box::new(t) as Box<StderrTerminal>) -} - -#[cfg(windows)] -/// Returns a Terminal wrapping stderr, or None if a terminal couldn't be -/// opened. -pub fn stderr() -> Option<Box<StderrTerminal>> { - TerminfoTerminal::new(io::stderr()) - .map(|t| Box::new(t) as Box<StderrTerminal>) - .or_else(|| WinConsole::new(io::stderr()).ok().map(|t| Box::new(t) as Box<StderrTerminal>)) -} - -/// Terminal color definitions -#[allow(missing_docs)] -pub mod color { - /// Number for a terminal color - pub type Color = u32; - - pub const BLACK: Color = 0; - pub const RED: Color = 1; - pub const GREEN: Color = 2; - pub const YELLOW: Color = 3; - pub const BLUE: Color = 4; - pub const MAGENTA: Color = 5; - pub const CYAN: Color = 6; - pub const WHITE: Color = 7; - - pub const BRIGHT_BLACK: Color = 8; - pub const BRIGHT_RED: Color = 9; - pub const BRIGHT_GREEN: Color = 10; - pub const BRIGHT_YELLOW: Color = 11; - pub const BRIGHT_BLUE: Color = 12; - pub const BRIGHT_MAGENTA: Color = 13; - pub const BRIGHT_CYAN: Color = 14; - pub const BRIGHT_WHITE: Color = 15; -} - -/// Terminal attributes for use with term.attr(). -/// -/// Most attributes can only be turned on and must be turned off with term.reset(). -/// The ones that can be turned off explicitly take a boolean value. -/// Color is also represented as an attribute for convenience. -#[derive(Debug, PartialEq, Eq, Copy, Clone)] -pub enum Attr { - /// Bold (or possibly bright) mode - Bold, - /// Dim mode, also called faint or half-bright. Often not supported - Dim, - /// Italics mode. Often not supported - Italic(bool), - /// Underline mode - Underline(bool), - /// Blink mode - Blink, - /// Standout mode. Often implemented as Reverse, sometimes coupled with Bold - Standout(bool), - /// Reverse mode, inverts the foreground and background colors - Reverse, - /// Secure mode, also called invis mode. Hides the printed text - Secure, - /// Convenience attribute to set the foreground color - ForegroundColor(color::Color), - /// Convenience attribute to set the background color - BackgroundColor(color::Color), -} - -/// A terminal with similar capabilities to an ANSI Terminal -/// (foreground/background colors etc). -pub trait Terminal: Write { - /// The terminal's output writer type. - type Output: Write; - - /// Sets the foreground color to the given color. - /// - /// If the color is a bright color, but the terminal only supports 8 colors, - /// the corresponding normal color will be used instead. - /// - /// Returns `Ok(true)` if the color was set, `Ok(false)` otherwise, and `Err(e)` - /// if there was an I/O error. - fn fg(&mut self, color: color::Color) -> io::Result<bool>; - - /// Sets the background color to the given color. - /// - /// If the color is a bright color, but the terminal only supports 8 colors, - /// the corresponding normal color will be used instead. - /// - /// Returns `Ok(true)` if the color was set, `Ok(false)` otherwise, and `Err(e)` - /// if there was an I/O error. - fn bg(&mut self, color: color::Color) -> io::Result<bool>; - - /// Sets the given terminal attribute, if supported. Returns `Ok(true)` - /// if the attribute was supported, `Ok(false)` otherwise, and `Err(e)` if - /// there was an I/O error. - fn attr(&mut self, attr: Attr) -> io::Result<bool>; - - /// Returns `true` if the given terminal attribute is supported. - fn supports_attr(&self, attr: Attr) -> bool; - - /// Resets all terminal attributes and colors to their defaults. - /// - /// Returns `Ok(true)` if the terminal was reset, `Ok(false)` otherwise, and `Err(e)` if there - /// was an I/O error. - /// - /// *Note: This does not flush.* - /// - /// That means the reset command may get buffered so, if you aren't planning on doing anything - /// else that might flush stdout's buffer (e.g., writing a line of text), you should flush after - /// calling reset. - fn reset(&mut self) -> io::Result<bool>; - - /// Gets an immutable reference to the stream inside - fn get_ref(&self) -> &Self::Output; - - /// Gets a mutable reference to the stream inside - fn get_mut(&mut self) -> &mut Self::Output; - - /// Returns the contained stream, destroying the `Terminal` - fn into_inner(self) -> Self::Output - where - Self: Sized; -} diff --git a/library/test/Cargo.toml b/library/test/Cargo.toml index 226557430df..80d6072e9b5 100644 --- a/library/test/Cargo.toml +++ b/library/test/Cargo.toml @@ -1,5 +1,4 @@ [package] -authors = ["The Rust Project Developers"] name = "test" version = "0.0.0" edition = "2018" @@ -10,7 +9,6 @@ crate-type = ["dylib", "rlib"] [dependencies] cfg-if = { version = "0.1.8", features = ['rustc-dep-of-std'] } getopts = { version = "0.2.21", features = ['rustc-dep-of-std'] } -term = { path = "../term" } std = { path = "../std" } core = { path = "../core" } libc = { version = "0.2", default-features = false } diff --git a/library/test/src/console.rs b/library/test/src/console.rs index 9cfc7eaf4bc..54e30a1fcd0 100644 --- a/library/test/src/console.rs +++ b/library/test/src/console.rs @@ -13,7 +13,7 @@ use super::{ formatters::{JsonFormatter, JunitFormatter, OutputFormatter, PrettyFormatter, TerseFormatter}, helpers::{concurrency::get_concurrency, metrics::MetricMap}, options::{Options, OutputFormat}, - run_tests, + run_tests, term, test_result::TestResult, time::{TestExecTime, TestSuiteExecTime}, types::{NamePadding, TestDesc, TestDescAndFn}, diff --git a/library/test/src/formatters/junit.rs b/library/test/src/formatters/junit.rs index ec66fc1219f..c4b0e1e5c23 100644 --- a/library/test/src/formatters/junit.rs +++ b/library/test/src/formatters/junit.rs @@ -79,7 +79,7 @@ impl<T: Write> OutputFormatter for JunitFormatter<T> { name=\"{}\" time=\"{}\">", class_name, test_name, - duration.as_secs() + duration.as_secs_f64() ))?; self.write_message("<failure type=\"assert\"/>")?; self.write_message("</testcase>")?; @@ -91,7 +91,7 @@ impl<T: Write> OutputFormatter for JunitFormatter<T> { name=\"{}\" time=\"{}\">", class_name, test_name, - duration.as_secs() + duration.as_secs_f64() ))?; self.write_message(&*format!("<failure message=\"{}\" type=\"assert\"/>", m))?; self.write_message("</testcase>")?; @@ -103,7 +103,7 @@ impl<T: Write> OutputFormatter for JunitFormatter<T> { name=\"{}\" time=\"{}\">", class_name, test_name, - duration.as_secs() + duration.as_secs_f64() ))?; self.write_message("<failure type=\"timeout\"/>")?; self.write_message("</testcase>")?; @@ -123,7 +123,7 @@ impl<T: Write> OutputFormatter for JunitFormatter<T> { name=\"{}\" time=\"{}\"/>", class_name, test_name, - duration.as_secs() + duration.as_secs_f64() ))?; } } diff --git a/library/test/src/formatters/pretty.rs b/library/test/src/formatters/pretty.rs index e17fc08a9ae..9cad71e30bd 100644 --- a/library/test/src/formatters/pretty.rs +++ b/library/test/src/formatters/pretty.rs @@ -4,6 +4,7 @@ use super::OutputFormatter; use crate::{ bench::fmt_bench_samples, console::{ConsoleTestState, OutputLocation}, + term, test_result::TestResult, time, types::TestDesc, diff --git a/library/test/src/formatters/terse.rs b/library/test/src/formatters/terse.rs index a2c223c494c..0c8215c5dac 100644 --- a/library/test/src/formatters/terse.rs +++ b/library/test/src/formatters/terse.rs @@ -4,6 +4,7 @@ use super::OutputFormatter; use crate::{ bench::fmt_bench_samples, console::{ConsoleTestState, OutputLocation}, + term, test_result::TestResult, time, types::NamePadding, diff --git a/library/test/src/lib.rs b/library/test/src/lib.rs index 3da4d434f48..251f099f28a 100644 --- a/library/test/src/lib.rs +++ b/library/test/src/lib.rs @@ -20,7 +20,7 @@ #![crate_name = "test"] #![unstable(feature = "test", issue = "50297")] #![doc(test(attr(deny(warnings))))] -#![cfg_attr(unix, feature(libc))] +#![feature(libc)] #![feature(rustc_private)] #![feature(nll)] #![feature(available_concurrency)] @@ -80,6 +80,7 @@ mod formatters; mod helpers; mod options; pub mod stats; +mod term; mod test_result; mod time; mod types; diff --git a/library/test/src/stats.rs b/library/test/src/stats.rs index 53f38894474..45fae9c76b4 100644 --- a/library/test/src/stats.rs +++ b/library/test/src/stats.rs @@ -19,7 +19,7 @@ pub trait Stats { /// ["Adaptive Precision Floating-Point Arithmetic and Fast Robust Geometric /// Predicates"][paper] /// - /// [paper]: http://www.cs.cmu.edu/~quake-papers/robust-arithmetic.ps + /// [paper]: https://www.cs.cmu.edu/~quake-papers/robust-arithmetic.ps fn sum(&self) -> f64; /// Minimum value of the samples. diff --git a/library/test/src/term.rs b/library/test/src/term.rs new file mode 100644 index 00000000000..b256ab7b8f8 --- /dev/null +++ b/library/test/src/term.rs @@ -0,0 +1,85 @@ +//! Terminal formatting module. +//! +//! This module provides the `Terminal` trait, which abstracts over an [ANSI +//! Terminal][ansi] to provide color printing, among other things. There are two +//! implementations, the `TerminfoTerminal`, which uses control characters from +//! a [terminfo][ti] database, and `WinConsole`, which uses the [Win32 Console +//! API][win]. +//! +//! [ansi]: https://en.wikipedia.org/wiki/ANSI_escape_code +//! [win]: https://docs.microsoft.com/en-us/windows/console/character-mode-applications +//! [ti]: https://en.wikipedia.org/wiki/Terminfo + +#![deny(missing_docs)] + +use std::io::{self, prelude::*}; + +pub(crate) use terminfo::TerminfoTerminal; +#[cfg(windows)] +pub(crate) use win::WinConsole; + +pub(crate) mod terminfo; + +#[cfg(windows)] +mod win; + +/// Alias for stdout terminals. +pub(crate) type StdoutTerminal = dyn Terminal + Send; + +#[cfg(not(windows))] +/// Returns a Terminal wrapping stdout, or None if a terminal couldn't be +/// opened. +pub(crate) fn stdout() -> Option<Box<StdoutTerminal>> { + TerminfoTerminal::new(io::stdout()).map(|t| Box::new(t) as Box<StdoutTerminal>) +} + +#[cfg(windows)] +/// Returns a Terminal wrapping stdout, or None if a terminal couldn't be +/// opened. +pub(crate) fn stdout() -> Option<Box<StdoutTerminal>> { + TerminfoTerminal::new(io::stdout()) + .map(|t| Box::new(t) as Box<StdoutTerminal>) + .or_else(|| WinConsole::new(io::stdout()).ok().map(|t| Box::new(t) as Box<StdoutTerminal>)) +} + +/// Terminal color definitions +#[allow(missing_docs)] +#[cfg_attr(not(windows), allow(dead_code))] +pub(crate) mod color { + /// Number for a terminal color + pub(crate) type Color = u32; + + pub(crate) const BLACK: Color = 0; + pub(crate) const RED: Color = 1; + pub(crate) const GREEN: Color = 2; + pub(crate) const YELLOW: Color = 3; + pub(crate) const BLUE: Color = 4; + pub(crate) const MAGENTA: Color = 5; + pub(crate) const CYAN: Color = 6; + pub(crate) const WHITE: Color = 7; +} + +/// A terminal with similar capabilities to an ANSI Terminal +/// (foreground/background colors etc). +pub trait Terminal: Write { + /// Sets the foreground color to the given color. + /// + /// If the color is a bright color, but the terminal only supports 8 colors, + /// the corresponding normal color will be used instead. + /// + /// Returns `Ok(true)` if the color was set, `Ok(false)` otherwise, and `Err(e)` + /// if there was an I/O error. + fn fg(&mut self, color: color::Color) -> io::Result<bool>; + + /// Resets all terminal attributes and colors to their defaults. + /// + /// Returns `Ok(true)` if the terminal was reset, `Ok(false)` otherwise, and `Err(e)` if there + /// was an I/O error. + /// + /// *Note: This does not flush.* + /// + /// That means the reset command may get buffered so, if you aren't planning on doing anything + /// else that might flush stdout's buffer (e.g., writing a line of text), you should flush after + /// calling reset. + fn reset(&mut self) -> io::Result<bool>; +} diff --git a/library/term/src/terminfo/mod.rs b/library/test/src/term/terminfo/mod.rs index fec59aaa0c2..f4c5a05d1e2 100644 --- a/library/term/src/terminfo/mod.rs +++ b/library/test/src/term/terminfo/mod.rs @@ -8,9 +8,8 @@ use std::fs::File; use std::io::{self, prelude::*, BufReader}; use std::path::Path; -use crate::color; -use crate::Attr; -use crate::Terminal; +use super::color; +use super::Terminal; use parm::{expand, Param, Variables}; use parser::compiled::{msys_terminfo, parse}; @@ -18,20 +17,20 @@ use searcher::get_dbpath_for_term; /// A parsed terminfo database entry. #[derive(Debug)] -pub struct TermInfo { +pub(crate) struct TermInfo { /// Names for the terminal - pub names: Vec<String>, + pub(crate) names: Vec<String>, /// Map of capability name to boolean value - pub bools: HashMap<String, bool>, + pub(crate) bools: HashMap<String, bool>, /// Map of capability name to numeric value - pub numbers: HashMap<String, u32>, + pub(crate) numbers: HashMap<String, u32>, /// Map of capability name to raw (unexpanded) string - pub strings: HashMap<String, Vec<u8>>, + pub(crate) strings: HashMap<String, Vec<u8>>, } /// A terminfo creation error. #[derive(Debug)] -pub enum Error { +pub(crate) enum Error { /// TermUnset Indicates that the environment doesn't include enough information to find /// the terminfo entry. TermUnset, @@ -64,7 +63,7 @@ impl fmt::Display for Error { impl TermInfo { /// Creates a TermInfo based on current environment. - pub fn from_env() -> Result<TermInfo, Error> { + pub(crate) fn from_env() -> Result<TermInfo, Error> { let term = match env::var("TERM") { Ok(name) => TermInfo::from_name(&name), Err(..) => return Err(Error::TermUnset), @@ -79,7 +78,7 @@ impl TermInfo { } /// Creates a TermInfo for the named terminal. - pub fn from_name(name: &str) -> Result<TermInfo, Error> { + pub(crate) fn from_name(name: &str) -> Result<TermInfo, Error> { get_dbpath_for_term(name) .ok_or_else(|| { Error::IoError(io::Error::new(io::ErrorKind::NotFound, "terminfo file not found")) @@ -88,7 +87,7 @@ impl TermInfo { } /// Parse the given TermInfo. - pub fn from_path<P: AsRef<Path>>(path: P) -> Result<TermInfo, Error> { + pub(crate) fn from_path<P: AsRef<Path>>(path: P) -> Result<TermInfo, Error> { Self::_from_path(path.as_ref()) } // Keep the metadata small @@ -99,43 +98,24 @@ impl TermInfo { } } -pub mod searcher; +pub(crate) mod searcher; /// TermInfo format parsing. -pub mod parser { +pub(crate) mod parser { //! ncurses-compatible compiled terminfo format parsing (term(5)) - pub mod compiled; -} -pub mod parm; - -fn cap_for_attr(attr: Attr) -> &'static str { - match attr { - Attr::Bold => "bold", - Attr::Dim => "dim", - Attr::Italic(true) => "sitm", - Attr::Italic(false) => "ritm", - Attr::Underline(true) => "smul", - Attr::Underline(false) => "rmul", - Attr::Blink => "blink", - Attr::Standout(true) => "smso", - Attr::Standout(false) => "rmso", - Attr::Reverse => "rev", - Attr::Secure => "invis", - Attr::ForegroundColor(_) => "setaf", - Attr::BackgroundColor(_) => "setab", - } + pub(crate) mod compiled; } +pub(crate) mod parm; /// A Terminal that knows how many colors it supports, with a reference to its /// parsed Terminfo database record. -pub struct TerminfoTerminal<T> { +pub(crate) struct TerminfoTerminal<T> { num_colors: u32, out: T, ti: TermInfo, } impl<T: Write + Send> Terminal for TerminfoTerminal<T> { - type Output = T; fn fg(&mut self, color: color::Color) -> io::Result<bool> { let color = self.dim_if_necessary(color); if self.num_colors > color { @@ -144,32 +124,6 @@ impl<T: Write + Send> Terminal for TerminfoTerminal<T> { Ok(false) } - fn bg(&mut self, color: color::Color) -> io::Result<bool> { - let color = self.dim_if_necessary(color); - if self.num_colors > color { - return self.apply_cap("setab", &[Param::Number(color as i32)]); - } - Ok(false) - } - - fn attr(&mut self, attr: Attr) -> io::Result<bool> { - match attr { - Attr::ForegroundColor(c) => self.fg(c), - Attr::BackgroundColor(c) => self.bg(c), - _ => self.apply_cap(cap_for_attr(attr), &[]), - } - } - - fn supports_attr(&self, attr: Attr) -> bool { - match attr { - Attr::ForegroundColor(_) | Attr::BackgroundColor(_) => self.num_colors > 0, - _ => { - let cap = cap_for_attr(attr); - self.ti.strings.get(cap).is_some() - } - } - } - fn reset(&mut self) -> io::Result<bool> { // are there any terminals that have color/attrs and not sgr0? // Try falling back to sgr, then op @@ -182,26 +136,11 @@ impl<T: Write + Send> Terminal for TerminfoTerminal<T> { }; self.out.write_all(&cmd).and(Ok(true)) } - - fn get_ref(&self) -> &T { - &self.out - } - - fn get_mut(&mut self) -> &mut T { - &mut self.out - } - - fn into_inner(self) -> T - where - Self: Sized, - { - self.out - } } impl<T: Write + Send> TerminfoTerminal<T> { /// Creates a new TerminfoTerminal with the given TermInfo and Write. - pub fn new_with_terminfo(out: T, terminfo: TermInfo) -> TerminfoTerminal<T> { + pub(crate) fn new_with_terminfo(out: T, terminfo: TermInfo) -> TerminfoTerminal<T> { let nc = if terminfo.strings.contains_key("setaf") && terminfo.strings.contains_key("setab") { terminfo.numbers.get("colors").map_or(0, |&n| n) @@ -215,7 +154,7 @@ impl<T: Write + Send> TerminfoTerminal<T> { /// Creates a new TerminfoTerminal for the current environment with the given Write. /// /// Returns `None` when the terminfo cannot be found or parsed. - pub fn new(out: T) -> Option<TerminfoTerminal<T>> { + pub(crate) fn new(out: T) -> Option<TerminfoTerminal<T>> { TermInfo::from_env().map(move |ti| TerminfoTerminal::new_with_terminfo(out, ti)).ok() } diff --git a/library/term/src/terminfo/parm.rs b/library/test/src/term/terminfo/parm.rs index 2e4e917891e..0d37eb7359d 100644 --- a/library/term/src/terminfo/parm.rs +++ b/library/test/src/term/terminfo/parm.rs @@ -35,13 +35,12 @@ enum FormatState { /// Types of parameters a capability can use #[allow(missing_docs)] #[derive(Clone)] -pub enum Param { - Words(String), +pub(crate) enum Param { Number(i32), } /// Container for static and dynamic variable arrays -pub struct Variables { +pub(crate) struct Variables { /// Static variables A-Z sta_va: [Param; 26], /// Dynamic variables a-z @@ -50,7 +49,7 @@ pub struct Variables { impl Variables { /// Returns a new zero-initialized Variables - pub fn new() -> Variables { + pub(crate) fn new() -> Variables { Variables { sta_va: [ Number(0), @@ -121,7 +120,11 @@ impl Variables { /// /// To be compatible with ncurses, `vars` should be the same between calls to `expand` for /// multiple capabilities for the same terminal. -pub fn expand(cap: &[u8], params: &[Param], vars: &mut Variables) -> Result<Vec<u8>, String> { +pub(crate) fn expand( + cap: &[u8], + params: &[Param], + vars: &mut Variables, +) -> Result<Vec<u8>, String> { let mut state = Nothing; // expanded cap will only rarely be larger than the cap itself @@ -168,7 +171,6 @@ pub fn expand(cap: &[u8], params: &[Param], vars: &mut Variables) -> Result<Vec< Some(Number(0)) => output.push(128u8), // Don't check bounds. ncurses just casts and truncates. Some(Number(c)) => output.push(c as u8), - Some(_) => return Err("a non-char was used with %c".to_string()), None => return Err("stack is empty".to_string()), } } @@ -178,7 +180,6 @@ pub fn expand(cap: &[u8], params: &[Param], vars: &mut Variables) -> Result<Vec< '\'' => state = CharConstant, '{' => state = IntConstant(0), 'l' => match stack.pop() { - Some(Words(s)) => stack.push(Number(s.len() as i32)), Some(_) => return Err("a non-str was used with %l".to_string()), None => return Err("stack is empty".to_string()), }, @@ -195,9 +196,6 @@ pub fn expand(cap: &[u8], params: &[Param], vars: &mut Variables) -> Result<Vec< 'm' => x % y, _ => unreachable!("All cases handled"), })), - (Some(_), Some(_)) => { - return Err(format!("non-numbers on stack with {}", cur)); - } _ => return Err("stack is empty".to_string()), } } @@ -216,9 +214,6 @@ pub fn expand(cap: &[u8], params: &[Param], vars: &mut Variables) -> Result<Vec< 0 }, )), - (Some(_), Some(_)) => { - return Err(format!("non-numbers on stack with {}", cur)); - } _ => return Err("stack is empty".to_string()), }, '!' | '~' => match stack.pop() { @@ -228,7 +223,6 @@ pub fn expand(cap: &[u8], params: &[Param], vars: &mut Variables) -> Result<Vec< '~' => !x, _ => unreachable!(), })), - Some(_) => return Err(format!("non-numbers on stack with {}", cur)), None => return Err("stack is empty".to_string()), }, 'i' => match (&mparams[0], &mparams[1]) { @@ -236,7 +230,6 @@ pub fn expand(cap: &[u8], params: &[Param], vars: &mut Variables) -> Result<Vec< mparams[0] = Number(x + 1); mparams[1] = Number(y + 1); } - _ => return Err("first two params not numbers with %i".to_string()), }, // printf-style support for %doxXs @@ -271,7 +264,6 @@ pub fn expand(cap: &[u8], params: &[Param], vars: &mut Variables) -> Result<Vec< 't' => match stack.pop() { Some(Number(0)) => state = SeekIfElse(0), Some(Number(_)) => (), - Some(_) => return Err("non-number on stack with conditional".to_string()), None => return Err("stack is empty".to_string()), }, 'e' => state = SeekIfEnd(0), @@ -480,15 +472,6 @@ impl FormatOp { _ => panic!("bad FormatOp char"), } } - fn to_char(self) -> char { - match self { - FormatOp::Digit => 'd', - FormatOp::Octal => 'o', - FormatOp::LowerHex => 'x', - FormatOp::UpperHex => 'X', - FormatOp::String => 's', - } - } } fn format(val: Param, op: FormatOp, flags: Flags) -> Result<Vec<u8>, String> { @@ -533,16 +516,6 @@ fn format(val: Param, op: FormatOp, flags: Flags) -> Result<Vec<u8>, String> { } .into_bytes() } - Words(s) => match op { - FormatOp::String => { - let mut s = s.into_bytes(); - if flags.precision > 0 && flags.precision < s.len() { - s.truncate(flags.precision); - } - s - } - _ => return Err(format!("non-string on stack with %{}", op.to_char())), - }, }; if flags.width > s.len() { let n = flags.width - s.len(); diff --git a/library/term/src/terminfo/parm/tests.rs b/library/test/src/term/terminfo/parm/tests.rs index 1cc0967c8f4..256d1aaf446 100644 --- a/library/term/src/terminfo/parm/tests.rs +++ b/library/test/src/term/terminfo/parm/tests.rs @@ -51,7 +51,10 @@ fn test_param_stack_failure_conditions() { for &cap in caps.iter() { let res = get_res("", cap, &[], vars); assert!(res.is_err(), "Op {} succeeded incorrectly with 0 stack entries", cap); - let p = if cap == "%s" || cap == "%l" { Words("foo".to_string()) } else { Number(97) }; + if cap == "%s" || cap == "%l" { + continue; + } + let p = Number(97); let res = get_res("%p1", cap, &[p], vars); assert!(res.is_ok(), "Op {} failed with 1 stack entry: {}", cap, res.unwrap_err()); } @@ -109,23 +112,6 @@ fn test_conditionals() { fn test_format() { let mut varstruct = Variables::new(); let vars = &mut varstruct; - assert_eq!( - expand( - b"%p1%s%p2%2s%p3%2s%p4%.2s", - &[ - Words("foo".to_string()), - Words("foo".to_string()), - Words("f".to_string()), - Words("foo".to_string()) - ], - vars - ), - Ok("foofoo ffo".bytes().collect::<Vec<_>>()) - ); - assert_eq!( - expand(b"%p1%:-4.2s", &[Words("foo".to_string())], vars), - Ok("fo ".bytes().collect::<Vec<_>>()) - ); assert_eq!( expand(b"%p1%d%p1%.3d%p1%5d%p1%:+d", &[Number(1)], vars), diff --git a/library/term/src/terminfo/parser/compiled.rs b/library/test/src/term/terminfo/parser/compiled.rs index fbc5aebdb2c..b24f3f8b05e 100644 --- a/library/term/src/terminfo/parser/compiled.rs +++ b/library/test/src/term/terminfo/parser/compiled.rs @@ -13,7 +13,7 @@ mod tests; // These are the orders ncurses uses in its compiled format (as of 5.9). Not sure if portable. #[rustfmt::skip] -pub static boolfnames: &[&str] = &["auto_left_margin", "auto_right_margin", +pub(crate) static boolfnames: &[&str] = &["auto_left_margin", "auto_right_margin", "no_esc_ctlc", "ceol_standout_glitch", "eat_newline_glitch", "erase_overstrike", "generic_type", "hard_copy", "has_meta_key", "has_status_line", "insert_null_glitch", "memory_above", "memory_below", "move_insert_mode", "move_standout_mode", "over_strike", "status_line_esc_ok", @@ -26,13 +26,13 @@ pub static boolfnames: &[&str] = &["auto_left_margin", "auto_right_margin", "return_does_clr_eol"]; #[rustfmt::skip] -pub static boolnames: &[&str] = &["bw", "am", "xsb", "xhp", "xenl", "eo", +pub(crate) static boolnames: &[&str] = &["bw", "am", "xsb", "xhp", "xenl", "eo", "gn", "hc", "km", "hs", "in", "db", "da", "mir", "msgr", "os", "eslok", "xt", "hz", "ul", "xon", "nxon", "mc5i", "chts", "nrrmc", "npc", "ndscr", "ccc", "bce", "hls", "xhpa", "crxm", "daisy", "xvpa", "sam", "cpix", "lpix", "OTbs", "OTns", "OTnc", "OTMT", "OTNL", "OTpt", "OTxr"]; #[rustfmt::skip] -pub static numfnames: &[&str] = &[ "columns", "init_tabs", "lines", +pub(crate) static numfnames: &[&str] = &[ "columns", "init_tabs", "lines", "lines_of_memory", "magic_cookie_glitch", "padding_baud_rate", "virtual_terminal", "width_status_line", "num_labels", "label_height", "label_width", "max_attributes", "maximum_windows", "max_colors", "max_pairs", "no_color_video", "buffer_capacity", @@ -43,13 +43,13 @@ pub static numfnames: &[&str] = &[ "columns", "init_tabs", "lines", "new_line_delay", "backspace_delay", "horizontal_tab_delay", "number_of_function_keys"]; #[rustfmt::skip] -pub static numnames: &[&str] = &[ "cols", "it", "lines", "lm", "xmc", "pb", +pub(crate) static numnames: &[&str] = &[ "cols", "it", "lines", "lm", "xmc", "pb", "vt", "wsl", "nlab", "lh", "lw", "ma", "wnum", "colors", "pairs", "ncv", "bufsz", "spinv", "spinh", "maddr", "mjump", "mcs", "mls", "npins", "orc", "orl", "orhi", "orvi", "cps", "widcs", "btns", "bitwin", "bitype", "UTug", "OTdC", "OTdN", "OTdB", "OTdT", "OTkn"]; #[rustfmt::skip] -pub static stringfnames: &[&str] = &[ "back_tab", "bell", "carriage_return", +pub(crate) static stringfnames: &[&str] = &[ "back_tab", "bell", "carriage_return", "change_scroll_region", "clear_all_tabs", "clear_screen", "clr_eol", "clr_eos", "column_address", "command_character", "cursor_address", "cursor_down", "cursor_home", "cursor_invisible", "cursor_left", "cursor_mem_address", "cursor_normal", "cursor_right", @@ -123,7 +123,7 @@ pub static stringfnames: &[&str] = &[ "back_tab", "bell", "carriage_return", "acs_plus", "memory_lock", "memory_unlock", "box_chars_1"]; #[rustfmt::skip] -pub static stringnames: &[&str] = &[ "cbt", "_", "cr", "csr", "tbc", "clear", +pub(crate) static stringnames: &[&str] = &[ "cbt", "_", "cr", "csr", "tbc", "clear", "_", "_", "hpa", "cmdch", "cup", "cud1", "home", "civis", "cub1", "mrcup", "cnorm", "cuf1", "ll", "cuu1", "cvvis", "dch1", "dl1", "dsl", "hd", "smacs", "blink", "bold", "smcup", "smdc", "dim", "smir", "invis", "prot", "rev", "smso", "smul", "ech", "rmacs", "sgr0", "rmcup", "rmdc", @@ -178,7 +178,7 @@ fn read_byte(r: &mut dyn io::Read) -> io::Result<u8> { /// Parse a compiled terminfo entry, using long capability names if `longnames` /// is true -pub fn parse(file: &mut dyn io::Read, longnames: bool) -> Result<TermInfo, String> { +pub(crate) fn parse(file: &mut dyn io::Read, longnames: bool) -> Result<TermInfo, String> { macro_rules! t( ($e:expr) => ( match $e { Ok(e) => e, @@ -317,7 +317,7 @@ pub fn parse(file: &mut dyn io::Read, longnames: bool) -> Result<TermInfo, Strin } /// Creates a dummy TermInfo struct for msys terminals -pub fn msys_terminfo() -> TermInfo { +pub(crate) fn msys_terminfo() -> TermInfo { let mut strings = HashMap::new(); strings.insert("sgr0".to_string(), b"\x1B[0m".to_vec()); strings.insert("bold".to_string(), b"\x1B[1m".to_vec()); diff --git a/library/term/src/terminfo/parser/compiled/tests.rs b/library/test/src/term/terminfo/parser/compiled/tests.rs index 8a9187b0495..8a9187b0495 100644 --- a/library/term/src/terminfo/parser/compiled/tests.rs +++ b/library/test/src/term/terminfo/parser/compiled/tests.rs diff --git a/library/term/src/terminfo/searcher.rs b/library/test/src/term/terminfo/searcher.rs index 5499e240e66..68e181a6895 100644 --- a/library/term/src/terminfo/searcher.rs +++ b/library/test/src/term/terminfo/searcher.rs @@ -11,7 +11,7 @@ mod tests; /// Return path to database entry for `term` #[allow(deprecated)] -pub fn get_dbpath_for_term(term: &str) -> Option<PathBuf> { +pub(crate) fn get_dbpath_for_term(term: &str) -> Option<PathBuf> { let mut dirs_to_search = Vec::new(); let first_char = term.chars().next()?; diff --git a/library/term/src/terminfo/searcher/tests.rs b/library/test/src/term/terminfo/searcher/tests.rs index 4227a585e2f..4227a585e2f 100644 --- a/library/term/src/terminfo/searcher/tests.rs +++ b/library/test/src/term/terminfo/searcher/tests.rs diff --git a/library/term/src/win.rs b/library/test/src/term/win.rs index c24cf9518aa..4bdbd6ee75f 100644 --- a/library/term/src/win.rs +++ b/library/test/src/term/win.rs @@ -5,12 +5,11 @@ use std::io; use std::io::prelude::*; -use crate::color; -use crate::Attr; -use crate::Terminal; +use super::color; +use super::Terminal; /// A Terminal implementation that uses the Win32 Console API. -pub struct WinConsole<T> { +pub(crate) struct WinConsole<T> { buf: T, def_foreground: color::Color, def_background: color::Color, @@ -115,7 +114,7 @@ impl<T: Write + Send + 'static> WinConsole<T> { } /// Returns `None` whenever the terminal cannot be created for some reason. - pub fn new(out: T) -> io::Result<WinConsole<T>> { + pub(crate) fn new(out: T) -> io::Result<WinConsole<T>> { use std::mem::MaybeUninit; let fg; @@ -154,8 +153,6 @@ impl<T: Write> Write for WinConsole<T> { } impl<T: Write + Send + 'static> Terminal for WinConsole<T> { - type Output = T; - fn fg(&mut self, color: color::Color) -> io::Result<bool> { self.foreground = color; self.apply(); @@ -163,38 +160,6 @@ impl<T: Write + Send + 'static> Terminal for WinConsole<T> { Ok(true) } - fn bg(&mut self, color: color::Color) -> io::Result<bool> { - self.background = color; - self.apply(); - - Ok(true) - } - - fn attr(&mut self, attr: Attr) -> io::Result<bool> { - match attr { - Attr::ForegroundColor(f) => { - self.foreground = f; - self.apply(); - Ok(true) - } - Attr::BackgroundColor(b) => { - self.background = b; - self.apply(); - Ok(true) - } - _ => Ok(false), - } - } - - fn supports_attr(&self, attr: Attr) -> bool { - // it claims support for underscore and reverse video, but I can't get - // it to do anything -cmr - match attr { - Attr::ForegroundColor(_) | Attr::BackgroundColor(_) => true, - _ => false, - } - } - fn reset(&mut self) -> io::Result<bool> { self.foreground = self.def_foreground; self.background = self.def_background; @@ -202,19 +167,4 @@ impl<T: Write + Send + 'static> Terminal for WinConsole<T> { Ok(true) } - - fn get_ref(&self) -> &T { - &self.buf - } - - fn get_mut(&mut self) -> &mut T { - &mut self.buf - } - - fn into_inner(self) -> T - where - Self: Sized, - { - self.buf - } } diff --git a/library/test/src/tests.rs b/library/test/src/tests.rs index 5a4a540b04e..794f7277004 100644 --- a/library/test/src/tests.rs +++ b/library/test/src/tests.rs @@ -61,9 +61,7 @@ fn one_ignored_one_unignored_test() -> Vec<TestDescAndFn> { ignore: true, should_panic: ShouldPanic::No, allow_fail: false, - #[cfg(not(bootstrap))] compile_fail: false, - #[cfg(not(bootstrap))] no_run: false, test_type: TestType::Unknown, }, @@ -75,9 +73,7 @@ fn one_ignored_one_unignored_test() -> Vec<TestDescAndFn> { ignore: false, should_panic: ShouldPanic::No, allow_fail: false, - #[cfg(not(bootstrap))] compile_fail: false, - #[cfg(not(bootstrap))] no_run: false, test_type: TestType::Unknown, }, @@ -97,9 +93,7 @@ pub fn do_not_run_ignored_tests() { ignore: true, should_panic: ShouldPanic::No, allow_fail: false, - #[cfg(not(bootstrap))] compile_fail: false, - #[cfg(not(bootstrap))] no_run: false, test_type: TestType::Unknown, }, @@ -120,9 +114,7 @@ pub fn ignored_tests_result_in_ignored() { ignore: true, should_panic: ShouldPanic::No, allow_fail: false, - #[cfg(not(bootstrap))] compile_fail: false, - #[cfg(not(bootstrap))] no_run: false, test_type: TestType::Unknown, }, @@ -147,9 +139,7 @@ fn test_should_panic() { ignore: false, should_panic: ShouldPanic::Yes, allow_fail: false, - #[cfg(not(bootstrap))] compile_fail: false, - #[cfg(not(bootstrap))] no_run: false, test_type: TestType::Unknown, }, @@ -174,9 +164,7 @@ fn test_should_panic_good_message() { ignore: false, should_panic: ShouldPanic::YesWithMessage("error message"), allow_fail: false, - #[cfg(not(bootstrap))] compile_fail: false, - #[cfg(not(bootstrap))] no_run: false, test_type: TestType::Unknown, }, @@ -206,9 +194,7 @@ fn test_should_panic_bad_message() { ignore: false, should_panic: ShouldPanic::YesWithMessage(expected), allow_fail: false, - #[cfg(not(bootstrap))] compile_fail: false, - #[cfg(not(bootstrap))] no_run: false, test_type: TestType::Unknown, }, @@ -242,9 +228,7 @@ fn test_should_panic_non_string_message_type() { ignore: false, should_panic: ShouldPanic::YesWithMessage(expected), allow_fail: false, - #[cfg(not(bootstrap))] compile_fail: false, - #[cfg(not(bootstrap))] no_run: false, test_type: TestType::Unknown, }, @@ -270,9 +254,7 @@ fn test_should_panic_but_succeeds() { ignore: false, should_panic, allow_fail: false, - #[cfg(not(bootstrap))] compile_fail: false, - #[cfg(not(bootstrap))] no_run: false, test_type: TestType::Unknown, }, @@ -306,9 +288,7 @@ fn report_time_test_template(report_time: bool) -> Option<TestExecTime> { ignore: false, should_panic: ShouldPanic::No, allow_fail: false, - #[cfg(not(bootstrap))] compile_fail: false, - #[cfg(not(bootstrap))] no_run: false, test_type: TestType::Unknown, }, @@ -343,9 +323,7 @@ fn time_test_failure_template(test_type: TestType) -> TestResult { ignore: false, should_panic: ShouldPanic::No, allow_fail: false, - #[cfg(not(bootstrap))] compile_fail: false, - #[cfg(not(bootstrap))] no_run: false, test_type, }, @@ -384,9 +362,7 @@ fn typed_test_desc(test_type: TestType) -> TestDesc { ignore: false, should_panic: ShouldPanic::No, allow_fail: false, - #[cfg(not(bootstrap))] compile_fail: false, - #[cfg(not(bootstrap))] no_run: false, test_type, } @@ -499,9 +475,7 @@ pub fn exclude_should_panic_option() { ignore: false, should_panic: ShouldPanic::Yes, allow_fail: false, - #[cfg(not(bootstrap))] compile_fail: false, - #[cfg(not(bootstrap))] no_run: false, test_type: TestType::Unknown, }, @@ -525,9 +499,7 @@ pub fn exact_filter_match() { ignore: false, should_panic: ShouldPanic::No, allow_fail: false, - #[cfg(not(bootstrap))] compile_fail: false, - #[cfg(not(bootstrap))] no_run: false, test_type: TestType::Unknown, }, @@ -621,9 +593,7 @@ pub fn sort_tests() { ignore: false, should_panic: ShouldPanic::No, allow_fail: false, - #[cfg(not(bootstrap))] compile_fail: false, - #[cfg(not(bootstrap))] no_run: false, test_type: TestType::Unknown, }, @@ -702,9 +672,7 @@ pub fn test_bench_no_iter() { ignore: false, should_panic: ShouldPanic::No, allow_fail: false, - #[cfg(not(bootstrap))] compile_fail: false, - #[cfg(not(bootstrap))] no_run: false, test_type: TestType::Unknown, }; @@ -726,9 +694,7 @@ pub fn test_bench_iter() { ignore: false, should_panic: ShouldPanic::No, allow_fail: false, - #[cfg(not(bootstrap))] compile_fail: false, - #[cfg(not(bootstrap))] no_run: false, test_type: TestType::Unknown, }; @@ -744,9 +710,7 @@ fn should_sort_failures_before_printing_them() { ignore: false, should_panic: ShouldPanic::No, allow_fail: false, - #[cfg(not(bootstrap))] compile_fail: false, - #[cfg(not(bootstrap))] no_run: false, test_type: TestType::Unknown, }; @@ -756,9 +720,7 @@ fn should_sort_failures_before_printing_them() { ignore: false, should_panic: ShouldPanic::No, allow_fail: false, - #[cfg(not(bootstrap))] compile_fail: false, - #[cfg(not(bootstrap))] no_run: false, test_type: TestType::Unknown, }; diff --git a/library/test/src/types.rs b/library/test/src/types.rs index 63907c71ea7..3512a57e8e4 100644 --- a/library/test/src/types.rs +++ b/library/test/src/types.rs @@ -124,9 +124,7 @@ pub struct TestDesc { pub ignore: bool, pub should_panic: options::ShouldPanic, pub allow_fail: bool, - #[cfg(not(bootstrap))] pub compile_fail: bool, - #[cfg(not(bootstrap))] pub no_run: bool, pub test_type: TestType, } @@ -147,7 +145,6 @@ impl TestDesc { /// Returns None for ignored test or that that are just run, otherwise give a description of the type of test. /// Descriptions include "should panic", "compile fail" and "compile". - #[cfg(not(bootstrap))] pub fn test_mode(&self) -> Option<&'static str> { if self.ignore { return None; @@ -169,11 +166,6 @@ impl TestDesc { } None } - - #[cfg(bootstrap)] - pub fn test_mode(&self) -> Option<&'static str> { - None - } } #[derive(Debug)] diff --git a/library/unwind/Cargo.toml b/library/unwind/Cargo.toml index c76ba7667d4..1941f2b5a00 100644 --- a/library/unwind/Cargo.toml +++ b/library/unwind/Cargo.toml @@ -1,5 +1,4 @@ [package] -authors = ["The Rust Project Developers"] name = "unwind" version = "0.0.0" license = "MIT OR Apache-2.0" @@ -21,7 +20,7 @@ compiler_builtins = "0.1.0" cfg-if = "0.1.8" [build-dependencies] -cc = "1.0.68" +cc = "1.0.69" [features] diff --git a/library/unwind/src/lib.rs b/library/unwind/src/lib.rs index eaeec72fbb5..53b13b9043b 100644 --- a/library/unwind/src/lib.rs +++ b/library/unwind/src/lib.rs @@ -3,8 +3,8 @@ #![feature(link_cfg)] #![feature(nll)] #![feature(staged_api)] -#![feature(unwind_attributes)] #![feature(static_nobundle)] +#![feature(c_unwind)] #![cfg_attr(not(target_env = "msvc"), feature(libc))] cfg_if::cfg_if! { @@ -13,6 +13,7 @@ cfg_if::cfg_if! { } else if #[cfg(any( target_os = "l4re", target_os = "none", + target_os = "espidf", ))] { // These "unix" family members do not have unwinder. // Note this also matches x86_64-unknown-none-linuxkernel. diff --git a/library/unwind/src/libunwind.rs b/library/unwind/src/libunwind.rs index faf554d285a..196be74decb 100644 --- a/library/unwind/src/libunwind.rs +++ b/library/unwind/src/libunwind.rs @@ -81,9 +81,10 @@ pub type _Unwind_Exception_Cleanup_Fn = all(feature = "llvm-libunwind", any(target_os = "fuchsia", target_os = "linux")), link(name = "unwind", kind = "static") )] -extern "C" { - #[unwind(allowed)] +extern "C-unwind" { pub fn _Unwind_Resume(exception: *mut _Unwind_Exception) -> !; +} +extern "C" { pub fn _Unwind_DeleteException(exception: *mut _Unwind_Exception); pub fn _Unwind_GetLanguageSpecificData(ctx: *mut _Unwind_Context) -> *mut c_void; pub fn _Unwind_GetRegionStart(ctx: *mut _Unwind_Context) -> _Unwind_Ptr; @@ -230,9 +231,10 @@ if #[cfg(not(all(target_os = "ios", target_arch = "arm")))] { #[cfg_attr(all(feature = "llvm-libunwind", any(target_os = "fuchsia", target_os = "linux")), link(name = "unwind", kind = "static"))] - extern "C" { - #[unwind(allowed)] + extern "C-unwind" { pub fn _Unwind_RaiseException(exception: *mut _Unwind_Exception) -> _Unwind_Reason_Code; + } + extern "C" { pub fn _Unwind_Backtrace(trace: _Unwind_Trace_Fn, trace_argument: *mut c_void) -> _Unwind_Reason_Code; @@ -242,8 +244,7 @@ if #[cfg(not(all(target_os = "ios", target_arch = "arm")))] { #[cfg_attr(all(feature = "llvm-libunwind", any(target_os = "fuchsia", target_os = "linux")), link(name = "unwind", kind = "static"))] - extern "C" { - #[unwind(allowed)] + extern "C-unwind" { pub fn _Unwind_SjLj_RaiseException(e: *mut _Unwind_Exception) -> _Unwind_Reason_Code; } |
