iterator sizing lib
xact
| -rw-r--r-- | Cargo.toml | 7 | ||||
| -rw-r--r-- | README.md | 2 | ||||
| -rw-r--r-- | src/lib.rs | 129 |
3 files changed, 132 insertions, 6 deletions
@@ -1,9 +1,12 @@ [package] name = "hinted" -version = "0.0.0" +version = "0.0.1" edition = "2021" authors = ["bend-n <[email protected]>"] license = "MIT" repository = "https://github.com/bend-n/hinted" exclude = [".gitignore"] -description = "small crate for providing a size hint on an iterator" +description = "small crate for providing a size hint and exact size on an iterator" + +[features] +nightly = [] @@ -1,3 +1,3 @@ # hinted -small library providing a `hinted` function to set the lower bound size hint of any iterator.
\ No newline at end of file +small library providing a `hinted` (and `has` to set the size) function to set the lower bound size hint of any iterator. @@ -1,9 +1,27 @@ +#![cfg_attr( + feature = "nightly", + feature( + trusted_len, + trusted_fused, + min_specialization, + trusted_random_access, + inplace_iteration, + doc_auto_cfg + ) +)] +#![no_std] +use core::iter::FusedIterator; +#[cfg(feature = "nightly")] +use core::iter::{ + InPlaceIterable, SourceIter, TrustedLen, TrustedRandomAccess, TrustedRandomAccessNoCoerce, +}; /// Provides a hint for an iterator. -pub struct Hinted<I: Iterator> { +#[derive(Clone, Debug)] +pub struct Hinted<I> { /// Wrapped iterator. - pub iter: I, + iter: I, /// Size hint, decreased on every call to [`next()`](Iterator::next). - pub hint: usize, + hint: usize, } /// Set the size hint for an iterator. @@ -11,9 +29,21 @@ pub trait HintExt: Iterator where Self: Sized, { + /// Sets the lower bound of [`Iterator::size_hint`]. Useful for collects etc. fn hinted(self, hint: usize) -> Hinted<Self> { Hinted { iter: self, hint } } + /// Implements [`ExactSizeIterator`] for any iterator, with a len provided by you. + /// This implements [`TrustedLen`](std::iter::TrustedLen) as well, so this function is unsafe. + /// + /// The resulting iterator will not return after the length has been reached. + /// + /// # Safety + /// + /// number of items *must* be `len`. + unsafe fn has(self, len: usize) -> Exactly<Self> { + Exactly { iter: self, len } + } } impl<I: Iterator> HintExt for I {} @@ -33,3 +63,96 @@ where (self.hint, self.iter.size_hint().1) } } +impl<I: DoubleEndedIterator> DoubleEndedIterator for Hinted<I> { + fn next_back(&mut self) -> Option<Self::Item> { + self.hint = self.hint.saturating_sub(1); + self.iter.next_back() + } +} + +impl<I: FusedIterator> FusedIterator for Hinted<I> {} +#[cfg(feature = "nightly")] +unsafe impl<I: TrustedRandomAccess> TrustedRandomAccess for Hinted<I> {} +#[cfg(feature = "nightly")] +unsafe impl<I: TrustedRandomAccessNoCoerce> TrustedRandomAccessNoCoerce for Hinted<I> { + const MAY_HAVE_SIDE_EFFECT: bool = true; +} +#[cfg(feature = "nightly")] +unsafe impl<I: SourceIter> SourceIter for Hinted<I> { + type Source = I::Source; + + #[inline] + unsafe fn as_inner(&mut self) -> &mut I::Source { + // SAFETY: unsafe function forwarding to unsafe function with the same requirements + unsafe { SourceIter::as_inner(&mut self.iter) } + } +} +#[cfg(feature = "nightly")] +unsafe impl<I: InPlaceIterable> InPlaceIterable for Hinted<I> { + const EXPAND_BY: Option<core::num::NonZero<usize>> = I::EXPAND_BY; + const MERGE_BY: Option<core::num::NonZero<usize>> = I::MERGE_BY; +} + +/// Provides a size for an iterator. +#[derive(Clone, Debug)] +pub struct Exactly<I> { + /// Wrapped iterator. + iter: I, + /// Exact size, decreased on every call to [`next()`](Iterator::next). + len: usize, +} + +/// Set the size hint for an iterator. +impl<I> Iterator for Exactly<I> +where + I: Iterator + Sized, +{ + type Item = <I as Iterator>::Item; + + fn next(&mut self) -> Option<Self::Item> { + self.len = unsafe { self.len.unchecked_sub(1) }; + self.iter.next() + } + + fn size_hint(&self) -> (usize, Option<usize>) { + (self.len, Some(self.len)) + } +} + +impl<I: Iterator> ExactSizeIterator for Exactly<I> { + fn len(&self) -> usize { + self.len + } +} +impl<I: DoubleEndedIterator> DoubleEndedIterator for Exactly<I> { + fn next_back(&mut self) -> Option<Self::Item> { + self.len = unsafe { self.len.unchecked_sub(1) }; + self.iter.next_back() + } +} +impl<I: FusedIterator> FusedIterator for Exactly<I> {} + +// SAFETY: see [`HintExt::has`]. +#[cfg(feature = "nightly")] +unsafe impl<I: Iterator> TrustedLen for Exactly<I> {} +#[cfg(feature = "nightly")] +unsafe impl<I: TrustedRandomAccess> TrustedRandomAccess for Exactly<I> {} +#[cfg(feature = "nightly")] +unsafe impl<I: TrustedRandomAccessNoCoerce> TrustedRandomAccessNoCoerce for Exactly<I> { + const MAY_HAVE_SIDE_EFFECT: bool = true; +} +#[cfg(feature = "nightly")] +unsafe impl<I: SourceIter> SourceIter for Exactly<I> { + type Source = I::Source; + + #[inline] + unsafe fn as_inner(&mut self) -> &mut I::Source { + // SAFETY: unsafe function forwarding to unsafe function with the same requirements + unsafe { SourceIter::as_inner(&mut self.iter) } + } +} +#[cfg(feature = "nightly")] +unsafe impl<I: InPlaceIterable> InPlaceIterable for Exactly<I> { + const EXPAND_BY: Option<core::num::NonZero<usize>> = I::EXPAND_BY; + const MERGE_BY: Option<core::num::NonZero<usize>> = I::MERGE_BY; +} |