Skip to content

Commit

Permalink
implement ConstSizeIntoIterator for &[T;N] in addition to [T;N]
Browse files Browse the repository at this point in the history
Due to #20400 the corresponding TrustedLen impls need a helper trait
instead of directly adding `Item = &[T;N]` bounds.
Since TrustedLen is a public trait this in turn means
the helper trait needs to be public. Since it's just a workaround
for a compiler deficit it's marked hidden, unstable and unsafe.
  • Loading branch information
the8472 committed Jul 16, 2021
1 parent 18a034f commit 8dd903c
Show file tree
Hide file tree
Showing 2 changed files with 68 additions and 3 deletions.
55 changes: 52 additions & 3 deletions library/core/src/iter/adapters/flatten.rs
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,22 @@ where
{
}

#[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.
///
Expand Down Expand Up @@ -239,8 +255,10 @@ where
}

#[unstable(feature = "trusted_len", issue = "37572")]
unsafe impl<T, I, const N: usize> TrustedLen for Flatten<I> where
I: Iterator<Item = [T; N]> + TrustedLen
unsafe impl<I> TrustedLen for Flatten<I>
where
I: TrustedLen,
<I as Iterator>::Item: TrustedConstSize,
{
}

Expand Down Expand Up @@ -475,10 +493,14 @@ where
}

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 {
impl<T> ConstSizeIntoIterator for T
where
T: IntoIterator,
{
#[inline]
default fn size() -> Option<usize> {
None
Expand All @@ -491,3 +513,30 @@ impl<T, const N: usize> ConstSizeIntoIterator for [T; N] {
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] {}
16 changes: 16 additions & 0 deletions library/core/tests/iter/adapters/flatten.rs
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,23 @@ fn test_trusted_len_flatten() {
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)));
}

0 comments on commit 8dd903c

Please sign in to comment.