Change __iterator_get_unchecked to work with TrustedRandomAccessNoCoerce

This commit is contained in:
Frank Steffahn 2021-07-01 18:54:02 +02:00
parent 69dd992f95
commit bbc6b2691e
8 changed files with 102 additions and 68 deletions

View file

@ -63,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`.

View file

@ -79,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`.

View file

@ -116,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`.

View file

@ -132,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

View file

@ -127,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`.

View file

@ -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 doesnt 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")]
@ -426,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.
@ -448,6 +478,9 @@ impl<A: Debug + TrustedRandomAccess, B: Debug + TrustedRandomAccess> ZipFmt<A, B
/// 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.
///
@ -463,6 +496,7 @@ impl<A: Debug + TrustedRandomAccess, B: Debug + TrustedRandomAccess> ZipFmt<A, B
/// * `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
@ -532,7 +566,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`.

View file

@ -676,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.

View file

@ -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");
}