mirror of
https://github.com/rust-lang/rust.git
synced 2024-10-31 06:22:00 +00:00
Auto merge of #85874 - steffahn:fix_unsound_zip_optimization, r=yaahc
Remove unsound TrustedRandomAccess implementations Removes the implementations that depend on the user-definable trait `Copy`. Fixes #85873 in the most straightforward way. <hr> _Edit:_ This PR now contains additional trait infrastructure to avoid performance regressions around in-place collect, see the discussion in this thread starting from the codegen test failure at https://github.com/rust-lang/rust/pull/85874#issuecomment-872327577. With this PR, `TrustedRandomAccess` gains additional documentation that specifically allows for and specifies the safety conditions around subtype coercions – those coercions can happen in safe Rust code with the `Zip` API’s usage of `TrustedRandomAccess`. This PR introduces a new supertrait of `TrustedRandomAccess`(currently named `TrustedRandomAccessNoCoerce`) that _doesn’t allow_ such coercions, which means it can be still be useful for optimizing cases such as in-place collect where no iterator is handed out to a user (who could do coercions) after a `get_unchecked` call; the benefit of the supertrait is that it doesn’t come with the additional safety conditions around supertraits either, so it can be implemented for more types than `TrustedRandomAccess`. The `TrustedRandomAccess` implementations for `vec::IntoIter`, `vec_deque::IntoIter`, and `array::IntoIter` are removed as they don’t conform with the newly documented safety conditions, this way unsoundness is removed. But this PR in turn (re-)adds a `TrustedRandomAccessNoCoerce` implementation for `vec::IntoIter` to avoid performance regressions from stable in a case of in-place collecting of `Vec`s [the above-mentioned codegen test failure]. Re-introducing the (currently nightly+beta-only) impls for `VecDeque`’s and `[T; N]`’s iterators is technically possible, but goes beyond the scope of this PR (i.e. it can happen in a future PR).
This commit is contained in:
commit
85237886df
@ -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};
|
||||
@ -104,11 +104,8 @@ impl<'a, T> Iterator for Iter<'a, T> {
|
||||
|
||||
#[inline]
|
||||
#[doc(hidden)]
|
||||
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
|
||||
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());
|
||||
@ -177,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;
|
||||
}
|
||||
|
@ -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};
|
||||
@ -90,11 +90,8 @@ impl<'a, T> Iterator for IterMut<'a, T> {
|
||||
|
||||
#[inline]
|
||||
#[doc(hidden)]
|
||||
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
|
||||
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());
|
||||
@ -146,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;
|
||||
}
|
||||
|
@ -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};
|
||||
@ -166,7 +168,7 @@ impl<T, A: Allocator> Iterator for IntoIter<T, A> {
|
||||
#[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)`
|
||||
@ -219,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,
|
||||
{
|
||||
|
@ -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};
|
||||
|
||||
@ -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) };
|
||||
@ -101,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;
|
||||
}
|
||||
|
||||
@ -124,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 {
|
||||
|
@ -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;
|
||||
|
||||
@ -61,7 +63,7 @@ where
|
||||
#[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`.
|
||||
@ -121,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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
@ -77,7 +79,7 @@ where
|
||||
#[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`.
|
||||
@ -137,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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
@ -114,7 +116,7 @@ where
|
||||
#[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`.
|
||||
@ -207,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;
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ use crate::intrinsics;
|
||||
use crate::iter::adapters::zip::try_get_unchecked;
|
||||
use crate::iter::{
|
||||
DoubleEndedIterator, ExactSizeIterator, FusedIterator, TrustedLen, TrustedRandomAccess,
|
||||
TrustedRandomAccessNoCoerce,
|
||||
};
|
||||
use crate::ops::Try;
|
||||
|
||||
@ -131,7 +132,7 @@ where
|
||||
#[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
|
||||
@ -221,9 +222,13 @@ 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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
@ -125,7 +127,7 @@ where
|
||||
#[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`.
|
||||
@ -187,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;
|
||||
}
|
||||
|
@ -51,6 +51,9 @@ 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;
|
||||
|
||||
|
@ -91,7 +91,7 @@ where
|
||||
#[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`.
|
||||
@ -126,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
|
||||
@ -137,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>) {
|
||||
@ -205,12 +218,35 @@ where
|
||||
|
||||
default unsafe fn get_unchecked(&mut self, _idx: usize) -> <Self as Iterator>::Item
|
||||
where
|
||||
Self: TrustedRandomAccess,
|
||||
Self: TrustedRandomAccessNoCoerce,
|
||||
{
|
||||
unreachable!("Always specialized");
|
||||
}
|
||||
}
|
||||
|
||||
#[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
|
||||
@ -330,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")]
|
||||
@ -354,6 +382,15 @@ unsafe impl<A, B> TrustedRandomAccess for Zip<A, B>
|
||||
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;
|
||||
}
|
||||
@ -417,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.
|
||||
@ -431,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.
|
||||
///
|
||||
/// `<Self as Iterator>::__iterator_get_unchecked` must be safe to call
|
||||
/// provided the following conditions are met.
|
||||
/// 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()`.
|
||||
///
|
||||
/// 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: Sized {
|
||||
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 TrustedRandomAccessNoCoerce: Sized {
|
||||
// Convenience method.
|
||||
fn size(&self) -> usize
|
||||
where
|
||||
@ -499,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`.
|
||||
|
@ -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,
|
||||
|
@ -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 {
|
||||
@ -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;
|
||||
}
|
||||
)*)
|
||||
@ -670,7 +676,7 @@ impl<A: Step> Iterator for ops::Range<A> {
|
||||
#[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.
|
||||
|
@ -5,7 +5,7 @@
|
||||
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};
|
||||
@ -3464,7 +3464,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");
|
||||
}
|
||||
|
@ -8,7 +8,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;
|
||||
@ -1312,7 +1312,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;
|
||||
}
|
||||
|
||||
@ -1477,7 +1481,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;
|
||||
}
|
||||
|
||||
@ -1639,7 +1647,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;
|
||||
}
|
||||
|
||||
@ -1793,7 +1805,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;
|
||||
}
|
||||
|
||||
@ -1944,7 +1960,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;
|
||||
}
|
||||
|
||||
@ -2182,7 +2202,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;
|
||||
}
|
||||
|
||||
@ -2295,7 +2319,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 +2485,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 +2650,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 +2812,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 +2971,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;
|
||||
}
|
||||
|
||||
|
@ -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};
|
||||
@ -345,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;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user