diff --git a/library/core/src/array/drain.rs b/library/core/src/array/drain.rs index 5fadf907b6219..a21a62a1c5164 100644 --- a/library/core/src/array/drain.rs +++ b/library/core/src/array/drain.rs @@ -1,7 +1,8 @@ use crate::iter::{TrustedLen, UncheckedIterator}; +use crate::marker::PhantomData; use crate::mem::ManuallyDrop; -use crate::ptr::drop_in_place; -use crate::slice; +use crate::ptr::NonNull; +use crate::slice::{self, DrainRaw}; /// A situationally-optimized version of `array.into_iter().for_each(func)`. /// @@ -21,37 +22,29 @@ pub(crate) fn drain_array_with( func: impl for<'a> FnOnce(Drain<'a, T>) -> R, ) -> R { let mut array = ManuallyDrop::new(array); - // SAFETY: Now that the local won't drop it, it's ok to construct the `Drain` which will. - let drain = Drain(array.iter_mut()); + // SAFETY: Now that the local won't drop it, it's ok to construct the `DrainRaw` which will. + // We ensure via the lifetime that it can't be used after the function returns, + // and thus the local `array` will always exist while iterating it. + let raw = unsafe { DrainRaw::from_parts(NonNull::new_unchecked(array.as_mut_ptr()), N) }; + let drain = Drain(raw, PhantomData); func(drain) } /// See [`drain_array_with`] -- this is `pub(crate)` only so it's allowed to be /// mentioned in the signature of that method. (Otherwise it hits `E0446`.) -// INVARIANT: It's ok to drop the remainder of the inner iterator. -pub(crate) struct Drain<'a, T>(slice::IterMut<'a, T>); - -impl Drop for Drain<'_, T> { - fn drop(&mut self) { - // SAFETY: By the type invariant, we're allowed to drop all these. - unsafe { drop_in_place(self.0.as_mut_slice()) } - } -} +pub(crate) struct Drain<'a, T>(slice::DrainRaw, PhantomData<&'a mut [T]>); impl Iterator for Drain<'_, T> { type Item = T; #[inline] fn next(&mut self) -> Option { - let p: *const T = self.0.next()?; - // SAFETY: The iterator was already advanced, so we won't drop this later. - Some(unsafe { p.read() }) + self.0.next() } #[inline] fn size_hint(&self) -> (usize, Option) { - let n = self.len(); - (n, Some(n)) + self.0.size_hint() } } @@ -69,8 +62,6 @@ impl UncheckedIterator for Drain<'_, T> { unsafe fn next_unchecked(&mut self) -> T { // SAFETY: `Drain` is 1:1 with the inner iterator, so if the caller promised // that there's an element left, the inner iterator has one too. - let p: *const T = unsafe { self.0.next_unchecked() }; - // SAFETY: The iterator was already advanced, so we won't drop this later. - unsafe { p.read() } + unsafe { self.0.next_unchecked() } } } diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index c5a1fca667bc3..7217643ee4981 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -214,6 +214,7 @@ #![feature(doc_cfg)] #![feature(doc_cfg_hide)] #![feature(doc_notable_trait)] +#![feature(dropck_eyepatch)] #![feature(extern_types)] #![feature(f128)] #![feature(f16)] diff --git a/library/core/src/slice/drain.rs b/library/core/src/slice/drain.rs new file mode 100644 index 0000000000000..d8e40f3003da0 --- /dev/null +++ b/library/core/src/slice/drain.rs @@ -0,0 +1,250 @@ +use crate::array; +use crate::fmt; +use crate::iter::{ + FusedIterator, TrustedFused, TrustedLen, TrustedRandomAccessNoCoerce, UncheckedIterator, +}; +use crate::mem::MaybeUninit; +use crate::num::NonZero; +use crate::ptr::NonNull; +use crate::slice::NonNullIter; + +/// An iterator which takes ownership of items out of a slice, dropping any +/// remaining items when the iterator drops. +/// +/// Note that, like a raw pointer, it's **up to you** to get the lifetime right. +/// In some ways it's actually harder to get right, as the iterator interface +/// appears safe, but as you promise when creating one of these, you still must +/// ensure that the mentioned memory is usable the whole time this lives. +/// +/// Ideally you won't be using this directly, but rather a version encapsulated +/// in a safer interface, like `vec::IntoIter`. +/// +/// This raw version may be removed in favour of a future language feature, +/// such as using `unsafe<'a> Drain<'a, T>` instead of `DrainRaw`. +#[unstable(feature = "slice_drain_raw_iter", issue = "none")] +pub struct DrainRaw(NonNullIter); + +#[unstable(feature = "slice_drain_raw_iter", issue = "none")] +// `may_dangle` is needed for compatibility with `vec::IntoIter` +unsafe impl<#[may_dangle] T> Drop for DrainRaw { + fn drop(&mut self) { + // When used in things like `vec::IntoIter`, the memory over which we're + // iterating might have been deallocated once we're running this drop. + // At the time of writing, Miri doesn't like `sub_ptr` between pointers + // into a deallocated allocation. So checking empty first -- which just + // needs pointer equality -- avoids that issue. + if !self.is_empty() { + let slice = self.as_nonnull_slice(); + // SAFETY: By type invariant, we're allowed to drop the rest of the items. + unsafe { slice.drop_in_place() }; + } + } +} + +#[unstable(feature = "slice_drain_raw_iter", issue = "none")] +impl fmt::Debug for DrainRaw { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_tuple("DrainRaw").field(&self.0.make_shortlived_slice()).finish() + } +} + +impl DrainRaw { + /// Creates a new iterator which moves the `len` items starting at `ptr` + /// while it's iterated, or drops them when the iterator is dropped. + /// + /// # Safety + /// + /// - `ptr` through `ptr.add(len)` must be a single allocated object + /// such that that it's sound to `offset` through it. + /// - All those elements must be readable, including being sufficiently aligned. + /// - All those elements are valid for dropping. + #[unstable(feature = "slice_drain_raw_iter", issue = "none")] + #[inline] + pub unsafe fn from_parts(ptr: NonNull, len: usize) -> Self { + // SAFETY: this function's safety conditions are stricter than NonNullIter, + // and include allowing the type to drop the items in `Drop`. + Self(unsafe { NonNullIter::from_parts(ptr, len) }) + } + + /// Returns a pointer to the remaining elements of the iterator + #[unstable(feature = "slice_drain_raw_iter", issue = "none")] + #[inline] + pub fn as_nonnull_slice(&self) -> NonNull<[T]> { + self.0.make_nonnull_slice() + } + + /// Equivalent to exhausting the iterator normally, but faster. + #[unstable(feature = "slice_drain_raw_iter", issue = "none")] + #[inline] + pub fn drop_remaining(&mut self) { + let all = self.forget_remaining(); + // SAFETY: We "forgot" these elements so our `Drop` won't drop them, + // so it's ok to drop them here without risking double-frees. + unsafe { all.drop_in_place() } + } + + /// Exhaust the iterator without actually dropping the rest of the items. + /// + /// Returns the forgotten items. + #[unstable(feature = "slice_drain_raw_iter", issue = "none")] + #[inline] + pub fn forget_remaining(&mut self) -> NonNull<[T]> { + let all = self.as_nonnull_slice(); + self.0.exhaust(); + all + } +} + +impl UncheckedIterator for DrainRaw { + #[inline] + unsafe fn next_unchecked(&mut self) -> T { + // SAFETY: we're a 1:1 mapping of the inner iterator, so if the caller + // proved we have another item, the inner iterator has another one too. + // Also, the `next_unchecked` means the returned item is no longer part + // of the inner iterator, and thus `read`ing it here -- and giving it + // to the caller who will (probably) drop it -- is ok. + unsafe { self.0.next_unchecked().read() } + } +} + +#[unstable(feature = "slice_drain_raw_iter", issue = "none")] +impl Iterator for DrainRaw { + type Item = T; + + #[inline] + fn next(&mut self) -> Option { + match self.0.next() { + // SAFETY: The `next` means the returned item is no longer part of + // the inner iterator, and thus `read`ing it here -- and giving it + // to the caller who will (probably) drop it -- is ok. + Some(ptr) => Some(unsafe { ptr.read() }), + None => None, + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.0.size_hint() + } + + #[inline] + fn advance_by(&mut self, n: usize) -> Result<(), NonZero> { + let clamped = self.len().min(n); + // SAFETY: By construction, `clamped` is always in-bounds. + // The skipped elements are removed from the inner iterator so won't be + // dropped in `Drop`, so dropping there here is fine. + unsafe { + let to_drop = self.0.skip_forward_unchecked(clamped); + to_drop.drop_in_place(); + } + NonZero::new(n - clamped).map_or(Ok(()), Err) + } + + #[inline] + fn count(self) -> usize { + self.len() + } + + #[inline] + fn next_chunk(&mut self) -> Result<[T; N], core::array::IntoIter> { + let len = self.len(); + let clamped = len.min(N); + + // SAFETY: By construction, `clamped` is always in-bounds. + let to_copy = unsafe { self.0.skip_forward_unchecked(clamped) }; + if len >= N { + // SAFETY: If we have more elements than were requested, they can be + // read directly because arrays need no extra alignment. + Ok(unsafe { to_copy.cast::<[T; N]>().read() }) + } else { + let mut raw_ary = MaybeUninit::uninit_array(); + // SAFETY: If we don't have enough elements left, then copy all the + // ones we do have into the local array, which cannot overlap because + // new locals are always distinct storage. + Err(unsafe { + MaybeUninit::::slice_as_mut_ptr(&mut raw_ary) + .copy_from_nonoverlapping(to_copy.as_mut_ptr(), len); + array::IntoIter::new_unchecked(raw_ary, 0..len) + }) + } + } + + unsafe fn __iterator_get_unchecked(&mut self, i: usize) -> Self::Item + where + Self: TrustedRandomAccessNoCoerce, + { + // SAFETY: the caller must guarantee that `i` is in bounds of the slice, + // so the `get_unchecked_mut(i)` is guaranteed to pointer to an element + // and thus guaranteed to be valid to dereference. + // + // Also note the implementation of `Self: TrustedRandomAccess` requires + // that `T: Copy` so reading elements from the buffer doesn't invalidate + // them for `Drop`. + unsafe { self.as_nonnull_slice().get_unchecked_mut(i).read() } + } +} + +#[unstable(feature = "slice_drain_raw_iter", issue = "none")] +impl DoubleEndedIterator for DrainRaw { + #[inline] + fn next_back(&mut self) -> Option { + match self.0.next_back() { + // SAFETY: The `next_back` means the returned item is no longer part of + // the inner iterator, and thus `read`ing it here -- and giving it + // to the caller who will (probably) drop it -- is ok. + Some(ptr) => Some(unsafe { ptr.read() }), + None => None, + } + } + + #[inline] + fn advance_back_by(&mut self, n: usize) -> Result<(), NonZero> { + let clamped = self.len().min(n); + // SAFETY: By construction, `clamped` is always in-bounds. + // The skipped elements are removed from the inner iterator so won't be + // dropped in `Drop`, so dropping there here is fine. + unsafe { + let to_drop = self.0.skip_backward_unchecked(clamped); + to_drop.drop_in_place(); + } + NonZero::new(n - clamped).map_or(Ok(()), Err) + } +} + +#[unstable(feature = "slice_drain_raw_iter", issue = "none")] +impl ExactSizeIterator for DrainRaw { + fn is_empty(&self) -> bool { + self.0.is_empty() + } + + fn len(&self) -> usize { + self.0.len() + } +} + +#[unstable(feature = "slice_drain_raw_iter", issue = "none")] +impl FusedIterator for DrainRaw {} + +#[unstable(feature = "slice_drain_raw_iter", issue = "none")] +#[doc(hidden)] +unsafe impl TrustedFused for DrainRaw {} + +#[unstable(feature = "slice_drain_raw_iter", issue = "none")] +unsafe impl TrustedLen for DrainRaw {} + +#[doc(hidden)] +#[unstable(issue = "none", feature = "std_internals")] +#[rustc_unsafe_specialization_marker] +pub trait NonDrop {} + +// T: Copy as approximation for !Drop since get_unchecked does not advance self.ptr +// and thus we can't implement drop-handling +#[unstable(issue = "none", feature = "std_internals")] +impl NonDrop for T {} + +// TrustedRandomAccess (without NoCoerce) must not be implemented because +// subtypes/supertypes of `T` might not be `NonDrop` +#[unstable(feature = "slice_drain_raw_iter", issue = "none")] +unsafe impl TrustedRandomAccessNoCoerce for DrainRaw { + const MAY_HAVE_SIDE_EFFECT: bool = false; +} diff --git a/library/core/src/slice/iter.rs b/library/core/src/slice/iter.rs index ca1920f98120b..af4e02e970ae1 100644 --- a/library/core/src/slice/iter.rs +++ b/library/core/src/slice/iter.rs @@ -78,7 +78,7 @@ pub struct Iter<'a, T: 'a> { #[stable(feature = "core_impl_debug", since = "1.9.0")] impl fmt::Debug for Iter<'_, T> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_tuple("Iter").field(&self.as_slice()).finish() + f.debug_tuple("Iter").field(&self.make_shortlived_slice()).finish() } } @@ -129,11 +129,32 @@ impl<'a, T> Iter<'a, T> { #[stable(feature = "iter_to_slice", since = "1.4.0")] #[inline] pub fn as_slice(&self) -> &'a [T] { - self.make_slice() + // SAFETY: the type invariant guarantees the pointer represents a valid slice + unsafe { self.make_nonnull_slice().as_ref() } + } + + #[inline] + unsafe fn non_null_to_item(p: NonNull) -> ::Item { + // SAFETY: the type invariant guarantees the pointer represents a valid reference + unsafe { p.as_ref() } + } +} + +#[stable(feature = "default_iters", since = "1.70.0")] +impl Default for Iter<'_, T> { + /// Creates an empty slice iterator. + /// + /// ``` + /// # use core::slice::Iter; + /// let iter: Iter<'_, u8> = Default::default(); + /// assert_eq!(iter.len(), 0); + /// ``` + fn default() -> Self { + (&[]).into_iter() } } -iterator! {struct Iter -> *const T, &'a T, const, {/* no mut */}, as_ref, { +iterator! {struct Iter<'a, T> => *const T, &'a T, { fn is_sorted_by(self, mut compare: F) -> bool where Self: Sized, @@ -201,7 +222,7 @@ pub struct IterMut<'a, T: 'a> { #[stable(feature = "core_impl_debug", since = "1.9.0")] impl fmt::Debug for IterMut<'_, T> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_tuple("IterMut").field(&self.make_slice()).finish() + f.debug_tuple("IterMut").field(&self.make_shortlived_slice()).finish() } } @@ -307,7 +328,8 @@ impl<'a, T> IterMut<'a, T> { #[stable(feature = "slice_iter_mut_as_slice", since = "1.53.0")] #[inline] pub fn as_slice(&self) -> &[T] { - self.make_slice() + // SAFETY: the type invariant guarantees the pointer represents a valid slice + unsafe { self.make_nonnull_slice().as_ref() } } /// Views the underlying data as a mutable subslice of the original data. @@ -350,6 +372,26 @@ impl<'a, T> IterMut<'a, T> { // for `from_raw_parts_mut` are fulfilled. unsafe { from_raw_parts_mut(self.ptr.as_ptr(), len!(self)) } } + + #[inline] + unsafe fn non_null_to_item(mut p: NonNull) -> ::Item { + // SAFETY: the type invariant guarantees the pointer represents a valid item + unsafe { p.as_mut() } + } +} + +#[stable(feature = "default_iters", since = "1.70.0")] +impl Default for IterMut<'_, T> { + /// Creates an empty slice iterator. + /// + /// ``` + /// # use core::slice::IterMut; + /// let iter: IterMut<'_, u8> = Default::default(); + /// assert_eq!(iter.len(), 0); + /// ``` + fn default() -> Self { + (&mut []).into_iter() + } } #[stable(feature = "slice_iter_mut_as_slice", since = "1.53.0")] @@ -367,7 +409,79 @@ impl AsRef<[T]> for IterMut<'_, T> { // } // } -iterator! {struct IterMut -> *mut T, &'a mut T, mut, {mut}, as_mut, {}} +iterator! {struct IterMut<'a, T> => *mut T, &'a mut T, {}} + +/// Iterator over all the `NonNull` pointers to the elements of a slice. +#[must_use = "iterators are lazy and do nothing unless consumed"] +pub struct NonNullIter { + /// The pointer to the next element to return, or the past-the-end location + /// if the iterator is empty. + /// + /// This address will be used for all ZST elements, never changed. + ptr: NonNull, + /// For non-ZSTs, the non-null pointer to the past-the-end element. + /// + /// For ZSTs, this is `ptr::without_provenance(len)`. + end_or_len: *const T, +} + +impl fmt::Debug for NonNullIter { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_tuple("NonNullIter").field(&self.make_shortlived_slice()).finish() + } +} + +impl NonNullIter { + /// Creates a new iterator over the `len` items starting at `ptr` + /// + /// # Safety + /// + /// - `ptr` through `ptr.add(len)` must be a single allocated object + /// such that that it's sound to `offset` through it. + /// - All those elements must be readable + /// - The caller must ensure both as long as the iterator is in use. + #[inline] + pub unsafe fn from_parts(ptr: NonNull, len: usize) -> Self { + // SAFETY: There are several things here: + // + // `ptr` has been obtained by `slice.as_ptr()` where `slice` is a valid + // reference thus it is non-NUL and safe to use and pass to + // `NonNull::new_unchecked` . + // + // Adding `slice.len()` to the starting pointer gives a pointer + // at the end of `slice`. `end` will never be dereferenced, only checked + // for direct pointer equality with `ptr` to check if the iterator is + // done. + // + // In the case of a ZST, the end pointer is just the length. It's never + // used as a pointer at all, and thus it's fine to have no provenance. + // + // See the `next_unchecked!` and `is_empty!` macros as well as the + // `post_inc_start` method for more information. + unsafe { + let end_or_len = + if T::IS_ZST { without_provenance_mut(len) } else { ptr.as_ptr().add(len) }; + + Self { ptr, end_or_len } + } + } + + #[inline] + pub fn exhaust(&mut self) { + if T::IS_ZST { + self.end_or_len = without_provenance_mut(0); + } else { + self.end_or_len = self.ptr.as_ptr(); + } + } + + #[inline] + fn non_null_to_item(p: NonNull) -> ::Item { + p + } +} + +iterator! {struct NonNullIter => *const T, NonNull, {}} /// An internal abstraction over the splitting iterators, so that /// splitn, splitn_mut etc can be implemented once. diff --git a/library/core/src/slice/iter/macros.rs b/library/core/src/slice/iter/macros.rs index c2a3819464410..c3730064716e0 100644 --- a/library/core/src/slice/iter/macros.rs +++ b/library/core/src/slice/iter/macros.rs @@ -63,14 +63,12 @@ macro_rules! len { // The shared definition of the `Iter` and `IterMut` iterators macro_rules! iterator { ( - struct $name:ident -> $ptr:ty, + struct $name:ty => $ptr:ty, $elem:ty, - $raw_mut:tt, - {$( $mut_:tt )?}, - $into_ref:ident, {$($extra:tt)*} ) => { - impl<'a, T> $name<'a, T> { + #[allow(unused_lifetimes)] + impl<'a, T> $name { /// Returns the last element and moves the end of the iterator backwards by 1. /// /// # Safety @@ -80,16 +78,22 @@ macro_rules! iterator { unsafe fn next_back_unchecked(&mut self) -> $elem { // SAFETY: the caller promised it's not empty, so // the offsetting is in-bounds and there's an element to return. - unsafe { self.pre_dec_end(1).$into_ref() } + unsafe { Self::non_null_to_item(self.pre_dec_end(1)) } } // Helper function for creating a slice from the iterator. - #[inline(always)] - fn make_slice(&self) -> &'a [T] { - // SAFETY: the iterator was created from a slice with pointer - // `self.ptr` and length `len!(self)`. This guarantees that all - // the prerequisites for `from_raw_parts` are fulfilled. - unsafe { from_raw_parts(self.ptr.as_ptr(), len!(self)) } + #[inline] + pub(crate) fn make_nonnull_slice(&self) -> NonNull<[T]> { + NonNull::slice_from_raw_parts(self.ptr, len!(self)) + } + + #[inline] + pub(crate) fn make_shortlived_slice<'b>(&'b self) -> &'b [T] { + // SAFETY: Everything expanded with this macro is readable while + // the iterator exists and is unchanged, so by tying this to the + // shorter-than-`'a` self borrow we can make this safe to call. + // (Elision would be fine here, but using `'b` for emphasis.) + unsafe { self.make_nonnull_slice().as_ref() } } // Helper function for moving the start of the iterator forwards by `offset` elements, @@ -133,10 +137,31 @@ macro_rules! iterator { }, ) } + + // This is not used on every type that uses this macro, but is more + // convenient to implement here so it can use `post_inc_start`. + #[allow(dead_code)] + #[inline] + pub(crate) unsafe fn skip_forward_unchecked(&mut self, offset: usize) -> NonNull<[T]> { + // SAFETY: The caller guarantees the provided offset is in-bounds. + let old_begin = unsafe { self.post_inc_start(offset) }; + NonNull::slice_from_raw_parts(old_begin, offset) + } + + // This is not used on every type that uses this macro, but is more + // convenient to implement here so it can use `pre_dec_end`. + #[allow(dead_code)] + #[inline] + pub(crate) unsafe fn skip_backward_unchecked(&mut self, offset: usize) -> NonNull<[T]> { + // SAFETY: The caller guarantees the provided offset is in-bounds. + let new_end = unsafe { self.pre_dec_end(offset) }; + NonNull::slice_from_raw_parts(new_end, offset) + } } + #[allow(unused_lifetimes)] #[stable(feature = "rust1", since = "1.0.0")] - impl ExactSizeIterator for $name<'_, T> { + impl<'a, T> ExactSizeIterator for $name { #[inline(always)] fn len(&self) -> usize { len!(self) @@ -148,8 +173,9 @@ macro_rules! iterator { } } + #[allow(unused_lifetimes)] #[stable(feature = "rust1", since = "1.0.0")] - impl<'a, T> Iterator for $name<'a, T> { + impl<'a, T> Iterator for $name { type Item = $elem; #[inline] @@ -229,7 +255,7 @@ macro_rules! iterator { loop { // SAFETY: the loop iterates `i in 0..len`, which always is in bounds of // the slice allocation - acc = f(acc, unsafe { & $( $mut_ )? *self.ptr.add(i).as_ptr() }); + acc = f(acc, unsafe { Self::non_null_to_item(self.ptr.add(i)) }); // SAFETY: `i` can't overflow since it'll only reach usize::MAX if the // slice had that length, in which case we'll break out of the loop // after the increment @@ -380,14 +406,15 @@ macro_rules! iterator { // that will access this subslice are called, so it is valid // for the returned reference to be mutable in the case of // `IterMut` - unsafe { & $( $mut_ )? * self.ptr.as_ptr().add(idx) } + unsafe { Self::non_null_to_item(self.ptr.add(idx)) } } $($extra)* } + #[allow(unused_lifetimes)] #[stable(feature = "rust1", since = "1.0.0")] - impl<'a, T> DoubleEndedIterator for $name<'a, T> { + impl<'a, T> DoubleEndedIterator for $name { #[inline] fn next_back(&mut self) -> Option<$elem> { // could be implemented with slices, but this avoids bounds checks @@ -429,35 +456,24 @@ macro_rules! iterator { } } + #[allow(unused_lifetimes)] #[stable(feature = "fused", since = "1.26.0")] - impl FusedIterator for $name<'_, T> {} + impl<'a, T> FusedIterator for $name {} + #[allow(unused_lifetimes)] #[unstable(feature = "trusted_len", issue = "37572")] - unsafe impl TrustedLen for $name<'_, T> {} + unsafe impl<'a, T> TrustedLen for $name {} - impl<'a, T> UncheckedIterator for $name<'a, T> { + #[allow(unused_lifetimes)] + impl<'a, T> UncheckedIterator for $name { #[inline] unsafe fn next_unchecked(&mut self) -> $elem { // SAFETY: The caller promised there's at least one more item. unsafe { - self.post_inc_start(1).$into_ref() + Self::non_null_to_item(self.post_inc_start(1)) } } } - - #[stable(feature = "default_iters", since = "1.70.0")] - impl Default for $name<'_, T> { - /// Creates an empty slice iterator. - /// - /// ``` - #[doc = concat!("# use core::slice::", stringify!($name), ";")] - #[doc = concat!("let iter: ", stringify!($name<'_, u8>), " = Default::default();")] - /// assert_eq!(iter.len(), 0); - /// ``` - fn default() -> Self { - (& $( $mut_ )? []).into_iter() - } - } } } diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 521c324820446..cebe170a34bcb 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -35,6 +35,7 @@ pub mod sort; mod ascii; mod cmp; +mod drain; pub(crate) mod index; mod iter; mod raw; @@ -70,6 +71,11 @@ pub use iter::ArrayWindows; #[stable(feature = "slice_group_by", since = "1.77.0")] pub use iter::{ChunkBy, ChunkByMut}; +use iter::NonNullIter; + +#[unstable(feature = "slice_drain_raw_iter", issue = "none")] +pub use drain::DrainRaw; + #[stable(feature = "split_inclusive", since = "1.51.0")] pub use iter::{SplitInclusive, SplitInclusiveMut};