#![cfg_attr(not(feature = "allow-unsafe"), forbid(unsafe_code))]
#![no_std]
#![no_builtins]
#![cfg_attr(not(kani), deny(missing_docs))]
#![doc = include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/README.md"))]
#![warn(clippy::all, clippy::pedantic)]
#![allow(clippy::inline_always)]
#![allow(clippy::elidable_lifetime_names)]
extern crate core;
use core::{fmt, mem, iter::{Iterator, DoubleEndedIterator, ExactSizeIterator, FusedIterator}};
#[cfg(kani)]
use kani::invariant::Invariant;
#[cfg(kani)]
macro_rules! requires {
($cond:expr $(, $msg:literal)?) => {
kani::assert($cond, requires!(@msg $cond $(, $msg)?))
};
(@msg $cond:expr, $msg:literal) => {
$msg
};
(@msg $cond:expr) => {
stringify!($cond)
};
}
#[cfg(not(kani))]
macro_rules! requires {
($cond:expr $(, $msg:literal)?) => {
debug_assert!($cond $(, $msg)?)
};
}
#[cfg(kani)]
macro_rules! bicond {
(($l:expr) <=> ($r:expr)) => {
kani::implies!($l => $r) && kani::implies!($r => $l)
}
}
#[repr(align(16))]
#[repr(u8)]
#[derive(Copy, Clone)]
enum Peeked<T> {
Empty,
#[allow(clippy::option_option)]
Peeked((Option<T>, Option<Option<T>>))
}
impl<T: fmt::Debug> fmt::Debug for Peeked<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Empty => f.write_str("Peeked::Empty"),
Self::Peeked((one, None)) => write!(f, "Peeked::Once({one:?})"),
Self::Peeked((one, Some(two))) => write!(f, "Peeked::Twice(({one:?}, {two:?}))")
}
}
}
macro_rules! is_some_and {
($opt:ident, $and:ident) => {
match &$opt {
Some(__inner) => $and(__inner),
None => false
}
}
}
enum MaybeTerm {
Size(usize),
Add(usize)
}
impl<T> Peeked<T> {
#[inline(always)]
#[must_use]
const fn once(elem: Option<T>) -> Self {
Self::Peeked((elem, None))
}
#[inline(always)]
#[must_use]
const fn twice(first: Option<T>, second: Option<T>) -> Self {
Self::Peeked((first, Some(second)))
}
#[inline]
#[must_use]
const fn num_peeked(&self) -> u8 {
match self {
Self::Empty => 0,
Self::Peeked((_, None)) => 1,
Self::Peeked((_, Some(_))) => 2
}
}
#[inline]
#[must_use]
const fn is_term(&self) -> bool {
matches!(self, Self::Peeked((None, _)))
}
#[inline]
#[must_use]
const fn maybe_term(&self) -> MaybeTerm {
match self {
Self::Peeked((Some(_), Some(None))) => MaybeTerm::Size(1),
Self::Peeked((None, _)) => MaybeTerm::Size(0),
Self::Peeked((Some(_), Some(Some(_)))) => MaybeTerm::Add(2),
Self::Peeked((Some(_), None)) => MaybeTerm::Add(1),
Self::Empty => MaybeTerm::Add(0)
}
}
#[inline(always)]
#[must_use]
#[allow(clippy::option_option)]
fn take_inner(&mut self) -> Option<Option<T>> {
match self {
Self::Empty => None,
Self::Peeked((elem, None)) => {
let res = elem.take();
*self = Peeked::Empty;
Some(res)
}
Self::Peeked((elem, Some(next))) => {
let res = elem.take();
*self = Peeked::once(next.take());
Some(res)
}
}
}
#[inline]
#[must_use]
#[cfg(not(kani))]
#[allow(clippy::option_option)]
fn take(&mut self) -> Option<Option<T>> {
self.take_inner()
}
#[inline]
#[must_use]
#[cfg(kani)]
pub fn take(&mut self) -> Option<Option<T>> {
let num_peeked = self.num_peeked();
let res = self.take_inner();
let post_num_peeked = self.num_peeked();
kani::assert(
bicond!((num_peeked == 2) <=> (post_num_peeked == 1)) &&
kani::implies!(num_peeked == 0 => post_num_peeked == 0) &&
kani::implies!(num_peeked == 1 => post_num_peeked == 0) &&
bicond!((num_peeked != 0) <=> (res.is_some())),
"`take` always approaches `Empty`"
);
res
}
#[inline(always)]
#[must_use]
fn drain(&mut self) -> Self { mem::replace(self, Self::Empty) }
#[inline]
#[must_use]
const fn is_full(&self) -> bool {
matches!(self, Self::Peeked((_, Some(_))))
}
#[inline]
#[must_use]
const fn non_empty(&self) -> bool {
!self.is_empty()
}
#[inline]
#[must_use]
const fn only_one(&self) -> bool {
matches!(self, Self::Peeked((_, None)))
}
#[inline]
#[must_use]
const fn is_empty(&self) -> bool {
matches!(self, Self::Empty)
}
#[inline]
#[cfg_attr(all(debug_assertions, not(kani)), track_caller)]
fn add_first_peek(&mut self, elem: Option<T>) {
requires!(
self.is_empty(),
"Precondition violated: `add_first_peek` was called when state was not Empty."
);
*self = Self::once(elem);
}
}
#[must_use = "You must not ignore `drain_if` operation's result"]
pub enum DrainIfBoth<'r, T: Iterator> {
Drained((T::Item, T::Item)),
Peek(Peek<'r, T>)
}
impl<'r, T: Iterator> DrainIfBoth<'r, T> {
#[must_use]
pub const fn is_drained(&self) -> bool {
matches!(self, Self::Drained(_))
}
#[inline]
pub fn drained(self) -> Option<(T::Item, T::Item)> {
match self {
Self::Drained(res) => Some(res),
Self::Peek(_) => None
}
}
#[inline]
pub fn peek(self) -> Option<Peek<'r, T>> {
match self {
Self::Peek(peek) => Some(peek),
Self::Drained(_) => None
}
}
#[inline]
pub fn map_or_else<E, F, R>(self, e: E, map: F) -> R
where
E: FnOnce(Peek<'r, T>) -> R,
F: FnOnce(T::Item, T::Item) -> R
{
match self {
Self::Drained((first, second)) => map(first, second),
Self::Peek(peek) => e(peek)
}
}
}
#[must_use = "You must not ignore `drain_if` operation's result"]
pub enum DrainIf<'r, T: Iterator> {
Drained((Option<T::Item>, T::Item)),
Peek(Peek<'r, T>)
}
impl<'r, T: Iterator> DrainIf<'r, T> {
#[must_use]
pub const fn is_drained(&self) -> bool {
matches!(self, Self::Drained(_))
}
#[inline]
pub fn drained(self) -> Option<(Option<T::Item>, T::Item)> {
match self {
Self::Drained(res) => Some(res),
Self::Peek(_) => None
}
}
#[inline]
pub fn peek(self) -> Option<Peek<'r, T>> {
match self {
Self::Peek(peek) => Some(peek),
Self::Drained(_) => None
}
}
#[inline]
pub fn map_or_else<E, F, R>(self, e: E, map: F) -> R
where
E: FnOnce(Peek<'r, T>) -> R,
F: FnOnce((Option<T::Item>, T::Item)) -> R
{
match self {
Self::Drained(res) => map(res),
Self::Peek(peek) => e(peek)
}
}
}
#[repr(transparent)]
pub struct Peek<'r, T: Iterator> {
src: &'r mut Peekable<T>
}
#[cfg(kani)]
impl<'r, T: Iterator> Invariant for Peek<'r, T> {
#[inline]
fn is_safe(&self) -> bool {
self.src.peeked.non_empty()
}
}
impl<'r, T> PartialEq<Option<&T::Item>> for Peek<'r, T>
where
T: Iterator,
<T as Iterator>::Item: PartialEq
{
#[inline(always)]
#[allow(clippy::ref_option_ref)]
fn eq(&self, other: &Option<&T::Item>) -> bool {
self.get().eq(other)
}
}
impl<'r, T> fmt::Debug for Peek<'r, T>
where
T: Iterator,
<T as Iterator>::Item: fmt::Debug
{
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_tuple("Peek").field(&self.get()).finish()
}
}
impl<'r, T: Iterator> Peek<'r, T> {
#[inline]
#[must_use]
#[cfg_attr(all(debug_assertions, not(kani)), track_caller)]
fn new(src: &'r mut Peekable<T>) -> Self {
requires!(
!src.peeked.is_empty(),
"Invariant violated on construction of Peek. Peeked state must not be Empty."
);
Self { src }
}
#[inline(always)]
#[cfg(feature = "allow-unsafe")]
const fn get_impl(&self) -> Option<&T::Item> {
match &self.src.peeked {
Peeked::Peeked((elem, _)) => elem.as_ref(),
Peeked::Empty => unsafe { core::hint::unreachable_unchecked() }
}
}
#[inline(always)]
#[cfg(not(feature = "allow-unsafe"))]
const fn get_impl(&self) -> Option<&T::Item> {
match &self.src.peeked {
Peeked::Peeked((elem, _)) => elem.as_ref(),
Peeked::Empty => None
}
}
#[inline]
#[must_use]
#[cfg(not(kani))]
pub const fn get(&self) -> Option<&T::Item> {
self.get_impl()
}
#[inline]
#[cfg(kani)]
pub fn get(&self) -> Option<&T::Item> {
kani::assert(self.is_safe(), "`Peek` invariant violated, state must be non-empty`");
self.get_impl()
}
#[inline(always)]
#[cfg(feature = "allow-unsafe")]
fn get_mut_impl(&mut self) -> Option<&mut T::Item> {
match &mut self.src.peeked {
Peeked::Peeked((elem, _)) => elem.as_mut(),
Peeked::Empty => unsafe { core::hint::unreachable_unchecked() }
}
}
#[inline(always)]
#[cfg(not(feature = "allow-unsafe"))]
fn get_mut_impl(&mut self) -> Option<&mut T::Item> {
match &mut self.src.peeked {
Peeked::Peeked((elem, _)) => elem.as_mut(),
Peeked::Empty => None
}
}
#[inline]
pub fn get_mut(&mut self) -> Option<&mut T::Item> {
#[cfg(kani)] { kani::assert(self.is_safe(), "`Peek` invariant violated, state must be non-empty`"); }
self.get_mut_impl()
}
#[must_use]
pub fn peek(&mut self) -> Option<&T::Item> {
#[cfg(kani)] { kani::assert(self.is_safe(), "`Peek` invariant violated, state must be non-empty`"); }
self.src.transition_forward();
#[cfg(kani)] {
kani::assert(
self.src.peeked.is_full(),
"`transition_forward` postcondition /\\ Peek's invariant -> is_full"
);
}
match &self.src.peeked {
Peeked::Peeked((_, Some(elem))) => elem.as_ref(),
_ => unreachable!()
}
}
#[must_use]
pub fn peek_mut(&mut self) -> Option<&mut T::Item> {
#[cfg(kani)] { kani::assert(self.is_safe(), "`Peek` invariant violated, state must be non-empty`"); }
self.src.transition_forward();
#[cfg(kani)] {
kani::assert(
self.src.peeked.is_full(),
"`transition_forward` postcondition /\\ Peek's invariant -> is_full"
);
}
match &mut self.src.peeked {
Peeked::Peeked((_, Some(elem))) => elem.as_mut(),
_ => unreachable!()
}
}
#[inline(always)]
#[cfg(feature = "allow-unsafe")]
fn consume_impl(self) -> Option<T::Item> {
unsafe {
self.src.peeked
.take()
.unwrap_unchecked()
}
}
#[inline(always)]
#[cfg(not(feature = "allow-unsafe"))]
fn consume_impl(self) -> Option<T::Item> {
self.src.peeked.take().unwrap()
}
#[inline]
#[allow(clippy::must_use_candidate)] pub fn consume(self) -> Option<T::Item> {
#[cfg(kani)] { kani::assert(self.is_safe(), "`Peek` invariant violated, state must be non-empty`"); }
self.consume_impl()
}
pub fn drain_if<F>(self, predicate: F) -> DrainIf<'r, T>
where F: FnOnce(&T::Item) -> bool
{
#[cfg(kani)] { kani::assert(self.is_safe(), "`Peek` invariant violated, state must be non-empty`"); }
self.src.transition_forward();
#[cfg(kani)] {
kani::assert(
self.src.peeked.is_full(),
"`transition_forward` postcondition /\\ Peek's invariant -> is_full"
);
}
match mem::replace(&mut self.src.peeked, Peeked::Empty) {
Peeked::Peeked((first, Some(second))) => match second {
Some(second) if predicate(&second) => DrainIf::Drained((first, second)),
_ => {
self.src.peeked = Peeked::twice(first, second);
DrainIf::Peek(self)
}
},
_ => unreachable!()
}
}
pub fn drain_if_both<F>(self, predicate: F) -> DrainIfBoth<'r, T>
where F: FnOnce(&T::Item, &T::Item) -> bool
{
#[cfg(kani)] { kani::assert(self.is_safe(), "`Peek` invariant violated, state must be non-empty`"); }
self.src.transition_forward();
#[cfg(kani)] {
kani::assert(
self.src.peeked.is_full(),
"`transition_forward` postcondition /\\ Peek's invariant -> is_full"
);
}
match mem::replace(&mut self.src.peeked, Peeked::Empty) {
Peeked::Peeked((first, Some(second))) => match (first, second) {
(Some(first), Some(second)) if predicate(&first, &second) => DrainIfBoth::Drained((first, second)),
(first, second) => {
self.src.peeked = Peeked::twice(first, second);
DrainIfBoth::Peek(self)
}
},
_ => unreachable!()
}
}
pub fn is_both<F>(&mut self, predicate: F) -> bool
where F: FnOnce(&T::Item, &T::Item) -> bool
{
#[cfg(kani)] { kani::assert(self.is_safe(), "`Peek` invariant violated, state must be non-empty`"); }
self.src.transition_forward();
#[cfg(kani)] {
kani::assert(
self.src.peeked.is_full(),
"`transition_forward` postcondition /\\ Peek's invariant -> is_full"
);
}
match &self.src.peeked {
Peeked::Peeked((first, Some(second))) => match (first, second) {
(Some(first), Some(second)) if predicate(&first, &second) => true,
_ => false,
},
_ => {
#[cfg(feature = "allow-unsafe")] {
unsafe { core::hint::unreachable_unchecked() }
}
#[cfg(not(feature = "allow-unsafe"))] {
unreachable!()
}
}
}
}
#[inline(always)]
fn take_some_second_impl(&mut self) -> Option<T::Item> {
#[cfg(kani)] {
kani::assert(
self.src.peeked.is_full(),
"`take_some_second` must only be called when the state is full."
);
kani::assert(
matches!(&self.src.peeked, Peeked::Peeked((_, Some(Some(_))))),
"`take_some_second` must only be called when the second peek is Some."
);
}
match &mut self.src.peeked {
Peeked::Peeked((_, second)) => {
#[cfg(feature = "allow-unsafe")] unsafe {
second.take().unwrap_unchecked()
}
#[cfg(not(feature = "allow-unsafe"))] {
second.take().unwrap()
}
},
#[cfg(feature = "allow-unsafe")]
_ => unsafe { core::hint::unreachable_unchecked() },
#[cfg(not(feature = "allow-unsafe"))]
_ => unreachable!()
}
}
#[inline(always)]
#[cfg(kani)]
fn take_some_second(&mut self) -> Option<T::Item> {
let res = self.take_some_second_impl();
kani::assert(
res.is_some(),
"`take_some_second` postcondition not satisfied, result must be Some."
);
kani::assert(
self.src.peeked.only_one(),
"`take_some_second` postcondition not satisfied, state must be only one"
);
res
}
#[inline(always)]
#[cfg(not(kani))]
fn take_some_second(&mut self) -> Option<T::Item> { self.take_some_second_impl() }
pub fn take_next_if<F>(&mut self, predicate: F) -> Option<T::Item>
where F: FnOnce(&T::Item) -> bool
{
#[cfg(kani)] { kani::assert(self.is_safe(), "`Peek` invariant violated, state must be non-empty`"); }
self.src.transition_forward();
#[cfg(kani)] {
kani::assert(
self.src.peeked.is_full(),
"`transition_forward` postcondition /\\ Peek's invariant -> is_full"
);
}
match &self.src.peeked {
Peeked::Peeked((_, Some(Some(second)))) if predicate(second) => self.take_some_second(),
_ => None
}
}
}
#[repr(transparent)]
#[must_use]
#[derive(Copy, Clone)]
pub struct PeekState<'r, T> {
peeked: &'r Peeked<T>
}
impl<'r, T> PeekState<'r, T> {
#[inline]
const fn new(peeked: &'r Peeked<T>) -> Self {
Self { peeked }
}
#[inline]
#[must_use]
pub const fn is_full(&self) -> bool {
self.peeked.is_full()
}
#[inline]
#[must_use]
pub const fn non_empty(&self) -> bool {
self.peeked.non_empty()
}
#[inline]
#[must_use]
pub const fn only_one(&self) -> bool {
self.peeked.only_one()
}
#[inline]
#[must_use]
pub const fn is_empty(&self) -> bool {
self.peeked.is_empty()
}
#[inline]
#[must_use]
pub const fn num_peeked(&self) -> u8 {
self.peeked.num_peeked()
}
}
#[derive(Copy, Clone)]
pub struct Peekable<T: Iterator> {
iter: T,
peeked: Peeked<T::Item>
}
impl<S: IntoIterator<IntoIter = T>, T: Iterator> From<S> for Peekable<T> {
#[inline]
fn from(into_iter: S) -> Self { Self::new(into_iter.into_iter()) }
}
impl<T: Iterator> Peekable<T> {
pub const fn new(iter: T) -> Self {
Self { iter, peeked: Peeked::Empty }
}
#[inline]
pub const fn peek_state(&self) -> PeekState<'_, T::Item> {
PeekState::new(&self.peeked)
}
#[inline]
fn transition_forward(&mut self) {
#[cfg(kani)]
let num_peeked = self.peeked.num_peeked();
#[cfg(kani)] { kani::assert(num_peeked != 0, "Precondition violated, state must not be empty"); }
if let Peeked::Peeked((_, sec @ None)) = &mut self.peeked {*sec = Some(self.iter.next())}
#[cfg(kani)] {
let post_num_peeked = self.peeked.num_peeked();
kani::assert(
bicond!((num_peeked == 1 || num_peeked == 2) <=> (post_num_peeked == 2)) &&
post_num_peeked == 2, "`transition_forward` always approaches `Twice`"
);
}
}
fn fill(&mut self) {
match &mut self.peeked {
Peeked::Empty => { self.peeked = Peeked::twice(self.iter.next(), self.iter.next()); },
Peeked::Peeked((_, Some(_))) => {},
Peeked::Peeked((_, sec @ None)) => { *sec = Some(self.iter.next()); }
}
#[cfg(kani)] {
kani::assert(
self.peeked.is_full(),
"Fill postcondition not satisfied. Peek state not `Twice`"
);
}
}
#[inline]
#[must_use]
pub fn peek(&mut self) -> Peek<'_, T> {
if self.peeked.is_empty() {
self.peeked.add_first_peek(self.iter.next());
}
Peek::new(self)
}
#[inline]
#[must_use]
pub fn peek_2(&mut self) -> Option<&T::Item> {
self.fill();
match &self.peeked {
Peeked::Peeked((_, Some(second))) => second.as_ref(),
_ => unreachable!()
}
}
#[inline]
#[must_use]
pub fn peek_2_mut(&mut self) -> Option<&mut T::Item> {
self.fill();
match &mut self.peeked {
Peeked::Peeked((_, Some(second))) => second.as_mut(),
_ => unreachable!()
}
}
#[inline]
pub fn next_if(&mut self, func: impl FnOnce(&T::Item) -> bool) -> Option<T::Item> {
match &mut self.peeked {
Peeked::Empty => match self.iter.next() {
Some(next) if func(&next) => Some(next),
other => { self.peeked = Peeked::once(other); None }
},
Peeked::Peeked((first, None)) => if is_some_and!(first, func) {
let res = first.take();
self.peeked = Peeked::Empty;
res
} else {
None
},
Peeked::Peeked((first, Some(second))) => if is_some_and!(first, func) {
mem::replace(first, second.take())
} else {
None
}
}
}
#[inline]
pub fn next_if_eq<E>(&mut self, expected: &E) -> Option<T::Item>
where
E: ?Sized,
<T as Iterator>::Item: PartialEq<E>,
{
self.next_if(|next| next.eq(expected))
}
}
impl<T> fmt::Debug for Peekable<T>
where
T: Iterator + fmt::Debug,
<T as Iterator>::Item: fmt::Debug
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Peekable")
.field("state", &self.peeked)
.field("iter", &self.iter)
.finish()
}
}
impl<T: Iterator> Iterator for Peekable<T> {
type Item = T::Item;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
match self.peeked.take() {
Some(v) => v,
None => self.iter.next(),
}
}
#[inline]
fn count(self) -> usize {
let amount = match self.peeked {
Peeked::Empty => 0,
Peeked::Peeked((None, _)) => return 0,
Peeked::Peeked((Some(_), None)) => 1,
Peeked::Peeked((Some(_), Some(next))) => match next {
Some(_) => 2,
None => return 1
},
};
amount + self.iter.count()
}
#[inline]
fn nth(&mut self, n: usize) -> Option<T::Item> {
if n == 0 {
self.peeked.take().unwrap_or_else(|| self.iter.next())
} else {
match self.peeked.drain() {
Peeked::Peeked((_, Some(elem))) => if n == 1 {
elem
} else {
self.iter.nth(n - 2)
},
Peeked::Peeked((_, None)) => self.iter.nth(n - 1),
Peeked::Empty => self.iter.nth(n)
}
}
}
#[inline]
fn last(mut self) -> Option<T::Item> {
match self.peeked.drain() {
Peeked::Empty => self.iter.last(),
Peeked::Peeked((None, _)) => None,
Peeked::Peeked((elem @ Some(_), Some(None))) => elem,
Peeked::Peeked((elem @ Some(_), None) | (Some(_), Some(elem @ Some(_)))) => self.iter
.last()
.or(elem)
}
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
let peek_len = match self.peeked.maybe_term() {
MaybeTerm::Size(known_size) => return (known_size, Some(known_size)),
MaybeTerm::Add(amnt) => amnt
};
let (lo, hi) = self.iter.size_hint();
let lo = lo.saturating_add(peek_len);
let hi = hi.and_then(|l| l.checked_add(peek_len));
(lo, hi)
}
#[inline]
fn fold<Acc, Fold>(mut self, init: Acc, mut fold: Fold) -> Acc
where
Self: Sized,
Fold: FnMut(Acc, Self::Item) -> Acc,
{
let acc = match self.peeked.drain() {
Peeked::Peeked((None, _)) => return init,
Peeked::Peeked((Some(first), Some(None))) => return fold(init, first),
Peeked::Peeked((Some(first), None)) => fold(init, first),
Peeked::Empty => init,
Peeked::Peeked((Some(first), Some(Some(second)))) => {
let acc = fold(init, first);
fold(acc, second)
}
};
self.iter.fold(acc, fold)
}
#[inline]
fn all<F>(&mut self, mut f: F) -> bool
where
Self: Sized,
F: FnMut(Self::Item) -> bool,
{
let peek_res = match self.peeked.drain() {
Peeked::Peeked((Some(elem), None)) => f(elem),
Peeked::Peeked((Some(first), Some(Some(second)))) => f(first) && f(second),
Peeked::Empty => true,
Peeked::Peeked((None, _)) => return true, Peeked::Peeked((Some(elem), Some(None))) => return f(elem) };
peek_res && self.iter.all(f)
}
#[inline]
fn any<F>(&mut self, mut f: F) -> bool
where
Self: Sized,
F: FnMut(Self::Item) -> bool,
{
let peek_res = match self.peeked.drain() {
Peeked::Peeked((Some(elem), None)) => f(elem),
Peeked::Peeked((Some(first), Some(Some(second)))) => f(first) || f(second),
Peeked::Empty => false,
Peeked::Peeked((None, _)) => return false, Peeked::Peeked((Some(elem), Some(None))) => return f(elem) };
peek_res || self.iter.any(f)
}
#[inline]
fn find<P>(&mut self, mut predicate: P) -> Option<Self::Item>
where
Self: Sized,
P: FnMut(&Self::Item) -> bool,
{
match self.peeked.drain() {
Peeked::Peeked((Some(elem), None)) => if predicate(&elem) { return Some(elem) } else { },
Peeked::Peeked((Some(elem), Some(Some(n_elem)))) => if predicate(&elem) {
self.peeked = Peeked::once(Some(n_elem));
return Some(elem)
} else if predicate(&n_elem) {
return Some(n_elem)
} else {
},
Peeked::Peeked((None, _)) => return None,
Peeked::Peeked((Some(elem), Some(None))) => return predicate(&elem).then_some(elem),
Peeked::Empty => {}
}
self.iter.find(predicate)
}
#[inline]
fn find_map<B, F>(&mut self, mut f: F) -> Option<B>
where
Self: Sized,
F: FnMut(Self::Item) -> Option<B>
{
match self.peeked.drain() {
Peeked::Peeked((Some(elem), None)) => if let Some(out) = f(elem) { return Some(out) } else {},
Peeked::Peeked((Some(elem), Some(Some(n_elem)))) => if let Some(out) = f(elem) {
self.peeked = Peeked::once(Some(n_elem));
return Some(out)
} else if let Some(n_out) = f(n_elem) {
return Some(n_out)
} else {
},
Peeked::Peeked((None, _)) => return None,
Peeked::Peeked((Some(elem), Some(None))) => return f(elem),
Peeked::Empty => {}
}
self.iter.find_map(f)
}
#[inline]
fn position<P>(&mut self, mut predicate: P) -> Option<usize>
where
Self: Sized,
P: FnMut(Self::Item) -> bool,
{
let offset = match self.peeked.drain() {
Peeked::Peeked((Some(elem), None)) => if predicate(elem) { return Some(0) } else { 1},
Peeked::Peeked((Some(elem), Some(Some(n_elem)))) => if predicate(elem) {
self.peeked = Peeked::once(Some(n_elem));
return Some(0)
} else if predicate(n_elem) {
return Some(1)
} else {
2
},
Peeked::Peeked((None, _)) => return None,
Peeked::Peeked((Some(elem), Some(None))) => return predicate(elem).then_some(0),
Peeked::Empty => 0
};
self.iter.position(predicate).map(|out| out + offset)
}
}
impl<T: DoubleEndedIterator> DoubleEndedIterator for Peekable<T> {
#[inline]
fn next_back(&mut self) -> Option<Self::Item> {
if self.peeked.is_term() { return None; }
match self.iter.next_back() {
res @ Some(_) => res,
None => match self.peeked.drain() {
Peeked::Empty => None,
Peeked::Peeked((elem, None | Some(None))) => elem,
Peeked::Peeked((s_last, Some(elem @ Some(_)))) => {
self.peeked = Peeked::once(s_last);
elem
}
}
}
}
#[inline]
fn rfold<Acc, Fold>(mut self, init: Acc, mut fold: Fold) -> Acc
where Fold: FnMut(Acc, Self::Item) -> Acc
{
match self.peeked.drain() {
Peeked::Peeked((None, _)) => init,
Peeked::Empty => self.iter.rfold(init, fold),
Peeked::Peeked((Some(last), None)) => {
let acc = self.iter.rfold(init, &mut fold);
fold(acc, last)
},
Peeked::Peeked((Some(last), Some(Some(s_last)))) => {
let acc = self.iter.rfold(init, &mut fold);
let acc = fold(acc, s_last);
fold(acc, last)
},
Peeked::Peeked((Some(last), Some(None))) => fold(init, last)
}
}
#[inline]
fn rfind<P>(&mut self, mut predicate: P) -> Option<Self::Item>
where
Self: Sized,
P: FnMut(&Self::Item) -> bool,
{
if let found @ Some(_) = self.iter.rfind(&mut predicate) {
return found;
}
match self.peeked.drain() {
Peeked::Empty | Peeked::Peeked((None, _)) => None,
Peeked::Peeked((Some(elem), None)) => predicate(&elem).then_some(elem),
Peeked::Peeked((Some(last), Some(None))) => predicate(&last).then_some(last),
Peeked::Peeked((Some(elem), Some(Some(first)))) => if predicate(&first) {
self.peeked = Peeked::once(Some(elem));
Some(first)
} else {
predicate(&elem).then_some(elem)
}
}
}
}
impl<T: ExactSizeIterator> ExactSizeIterator for Peekable<T> {
#[inline]
fn len(&self) -> usize {
let peek_len = match self.peeked.maybe_term() {
MaybeTerm::Size(known_size) => return known_size,
MaybeTerm::Add(amnt) => amnt
};
self.iter.len() + peek_len
}
}
impl<T: FusedIterator> FusedIterator for Peekable<T> {}
#[cfg(test)]
mod tests {
extern crate alloc;
use super::*;
use alloc::{format, vec::Vec};
use proptest::prelude::*;
#[test]
fn find_map_peek_2_drain() {
let collection = [1, 2, 3, 4, 5];
let mut iter = Peekable::new(collection.iter());
let mut iter_spec = collection.iter();
let _ = iter.peek_2();
assert_eq!(
iter.find_map(|elem| u8::try_from(*elem).ok()).unwrap(),
iter_spec.find_map(|elem| u8::try_from(*elem).ok()).unwrap()
);
assert_eq!(
iter.find_map(|elem| u8::try_from(*elem).ok()).unwrap(),
iter_spec.find_map(|elem| u8::try_from(*elem).ok()).unwrap()
);
assert_eq!(
iter.find_map(|elem| u8::try_from(*elem).ok()).unwrap(),
iter_spec.find_map(|elem| u8::try_from(*elem).ok()).unwrap()
);
}
proptest! {
#![proptest_config(ProptestConfig::with_cases(50_000))]
#[test]
fn iter_find(collection in any::<Vec<u8>>(), to_find in any::<u8>()) {
match Peekable::new(collection.iter()).find(|elem| *elem == &to_find) {
Some(elem) => prop_assert_eq!(*elem, to_find),
None => prop_assert!(collection.into_iter().find(|elem| elem == &to_find).is_none())
}
}
#[test]
fn iter_find_with_peeked(collection in any::<Vec<u8>>(), to_find in any::<u8>()) {
let mut iter = Peekable::new(collection.iter());
let _ = iter.peek();
match iter.find(|elem| *elem == &to_find) {
Some(elem) => prop_assert_eq!(*elem, to_find),
None => prop_assert!(collection.into_iter().find(|elem| elem == &to_find).is_none())
}
}
#[test]
fn iter_find_with_peeked_2(collection in any::<Vec<u8>>(), to_find in any::<u8>()) {
let mut iter = Peekable::new(collection.iter());
let _ = iter.peek_2();
match iter.find(|elem| *elem == &to_find) {
Some(elem) => prop_assert_eq!(*elem, to_find),
None => prop_assert!(collection.into_iter().find(|elem| elem == &to_find).is_none())
}
}
#[test]
fn iter_find_many(collection in any::<Vec<u8>>(), to_find in any::<u8>(), times in 0..7usize) {
let mut iter = Peekable::new(collection.iter());
let mut iter_spec = collection.iter();
for _ in 0..times {
match iter.find(|elem| *elem == &to_find) {
Some(elem) => prop_assert_eq!(elem, iter_spec.find(|elem| *elem == &to_find).unwrap()),
None => prop_assert!(iter_spec.find(|elem| *elem == &to_find).is_none())
}
}
}
#[test]
fn iter_find_many_peeked(collection in any::<Vec<u8>>(), to_find in any::<u8>(), times in 0..7usize) {
let mut iter = Peekable::new(collection.iter());
let mut iter_spec = collection.iter();
let _ = iter.peek();
for _ in 0..times {
match iter.find(|elem| *elem == &to_find) {
Some(elem) => prop_assert_eq!(elem, iter_spec.find(|elem| *elem == &to_find).unwrap()),
None => prop_assert!(iter_spec.find(|elem| *elem == &to_find).is_none())
}
}
}
#[test]
fn iter_find_many_peeked_2(collection in any::<Vec<u8>>(), to_find in any::<u8>(), times in 0..7usize) {
let mut iter = Peekable::new(collection.iter());
let mut iter_spec = collection.iter();
let _ = iter.peek_2();
for _ in 0..times {
match iter.find(|elem| *elem == &to_find) {
Some(elem) => prop_assert_eq!(elem, iter_spec.find(|elem| *elem == &to_find).unwrap()),
None => prop_assert!(iter_spec.find(|elem| *elem == &to_find).is_none())
}
}
}
#[test]
fn iter_position(collection in any::<Vec<u8>>(), to_find in any::<u8>()) {
match Peekable::new(collection.iter()).position(|elem| elem == &to_find) {
Some(pos) => prop_assert_eq!(pos, collection.into_iter().position(|elem| elem == to_find).unwrap()),
None => prop_assert!(collection.into_iter().position(|elem| elem == to_find).is_none())
}
}
#[test]
fn iter_position_peeked(collection in any::<Vec<u8>>(), to_find in any::<u8>()) {
let mut iter = Peekable::new(collection.iter());
let _ = iter.peek();
match iter.position(|elem| elem == &to_find) {
Some(pos) => prop_assert_eq!(pos, collection.into_iter().position(|elem| elem == to_find).unwrap()),
None => prop_assert!(collection.into_iter().position(|elem| elem == to_find).is_none())
}
}
#[test]
fn iter_position_peeked_2(collection in any::<Vec<u8>>(), to_find in any::<u8>()) {
let mut iter = Peekable::new(collection.iter());
let _ = iter.peek_2();
match iter.position(|elem| elem == &to_find) {
Some(pos) => prop_assert_eq!(pos, collection.into_iter().position(|elem| elem == to_find).unwrap()),
None => prop_assert!(collection.into_iter().position(|elem| elem == to_find).is_none())
}
}
#[test]
fn iter_any(collection in any::<Vec<u8>>(), to_find in any::<u8>()) {
if Peekable::new(collection.iter()).any(|elem| elem == &to_find) {
prop_assert!(collection.into_iter().any(|elem| elem == to_find))
} else {
prop_assert!(!collection.into_iter().any(|elem| elem == to_find))
}
}
#[test]
fn iter_any_peeked(collection in any::<Vec<u8>>(), to_find in any::<u8>()) {
let mut iter = Peekable::new(collection.iter());
let _ = iter.peek();
if iter.any(|elem| elem == &to_find) {
prop_assert!(collection.into_iter().any(|elem| elem == to_find))
} else {
prop_assert!(!collection.into_iter().any(|elem| elem == to_find))
}
}
#[test]
fn iter_any_peeked_2(collection in any::<Vec<u8>>(), to_find in any::<u8>()) {
let mut iter = Peekable::new(collection.iter());
let _ = iter.peek_2();
if iter.any(|elem| elem == &to_find) {
prop_assert!(collection.into_iter().any(|elem| elem == to_find))
} else {
prop_assert!(!collection.into_iter().any(|elem| elem == to_find))
}
}
#[test]
fn iter_all(collection in any::<Vec<u8>>(), to_find in any::<u8>()) {
if Peekable::new(collection.iter()).all(|elem| elem == &to_find) {
prop_assert!(collection.into_iter().all(|elem| elem == to_find))
} else {
prop_assert!(!collection.into_iter().all(|elem| elem == to_find))
}
}
#[test]
fn iter_all_peeked(collection in any::<Vec<u8>>(), to_find in any::<u8>()) {
let mut iter = Peekable::new(collection.iter());
let _ = iter.peek();
if iter.all(|elem| elem == &to_find) {
prop_assert!(collection.into_iter().all(|elem| elem == to_find))
} else {
prop_assert!(!collection.into_iter().all(|elem| elem == to_find))
}
}
#[test]
fn iter_all_peeked_2(collection in any::<Vec<u8>>(), to_find in any::<u8>()) {
let mut iter = Peekable::new(collection.iter());
let _ = iter.peek_2();
if iter.all(|elem| elem == &to_find) {
prop_assert!(collection.into_iter().all(|elem| elem == to_find))
} else {
prop_assert!(!collection.into_iter().all(|elem| elem == to_find))
}
}
#[test]
fn iter_nth(amnt in 0..16usize) {
let mut collection = 0..=16;
let res = Peekable::new(collection.clone()).nth(amnt);
prop_assert_eq!(res, collection.nth(amnt));
}
#[test]
fn iter_nth_peeked(amnt in 0..16usize) {
let mut collection = 0..=16;
let mut iter = Peekable::new(collection.clone());
let _ = iter.peek();
let res = iter.nth(amnt);
prop_assert_eq!(res, collection.nth(amnt));
}
#[test]
fn iter_nth_peeked_2(amnt in 0..16usize) {
let mut collection = 0..=16;
let mut iter = Peekable::new(collection.clone());
let _ = iter.peek_2();
let res = iter.nth(amnt);
prop_assert_eq!(res, collection.nth(amnt));
}
#[test]
fn iter_find_map(collection in any::<Vec<usize>>()) {
match Peekable::new(collection.iter()).find_map(|elem| u8::try_from(*elem).ok()) {
Some(m) => prop_assert_eq!(m, collection.into_iter().find_map(|elem| u8::try_from(elem).ok()).unwrap()),
None => prop_assert!(collection.into_iter().find_map(|elem| u8::try_from(elem).ok()).is_none())
}
}
#[test]
fn iter_find_map_peeked(collection in any::<Vec<usize>>()) {
let mut iter = Peekable::new(collection.iter());
let _ = iter.peek();
match iter.find_map(|elem| u8::try_from(*elem).ok()) {
Some(m) => prop_assert_eq!(m, collection.into_iter().find_map(|elem| u8::try_from(elem).ok()).unwrap()),
None => prop_assert!(collection.into_iter().find_map(|elem| u8::try_from(elem).ok()).is_none())
}
}
#[test]
fn iter_find_map_peeked_2(collection in any::<Vec<usize>>()) {
let mut iter = Peekable::new(collection.iter());
let _ = iter.peek_2();
match iter.find_map(|elem| u8::try_from(*elem).ok()) {
Some(m) => prop_assert_eq!(m, collection.into_iter().find_map(|elem| u8::try_from(elem).ok()).unwrap()),
None => prop_assert!(collection.into_iter().find_map(|elem| u8::try_from(elem).ok()).is_none())
}
}
#[test]
fn iter_find_map_many(collection in any::<Vec<usize>>(), times in 1..7usize) {
let mut iter = Peekable::new(collection.iter());
let mut iter_spec = collection.iter();
for _ in 0..times {
prop_assert_eq!(
iter.find_map(|elem| u8::try_from(*elem).ok()),
iter_spec.find_map(|elem| u8::try_from(*elem).ok())
);
}
}
#[test]
fn iter_find_map_many_peeked(collection in any::<Vec<usize>>(), times in 1..7usize) {
let mut iter = Peekable::new(collection.iter());
let mut iter_spec = collection.iter();
let _ = iter.peek();
for _ in 0..times {
prop_assert_eq!(
iter.find_map(|elem| u8::try_from(*elem).ok()),
iter_spec.find_map(|elem| u8::try_from(*elem).ok())
);
}
}
#[test]
fn iter_find_map_many_peeked_2(collection in any::<Vec<usize>>(), times in 1..16usize) {
let mut iter = Peekable::new(collection.iter());
let mut iter_spec = collection.iter();
let _ = iter.peek_2();
for _ in 0..times {
prop_assert_eq!(
iter.find_map(|elem| u16::try_from(*elem).ok()),
iter_spec.find_map(|elem| u16::try_from(*elem).ok())
);
}
}
#[test]
fn iter_last(collection in any::<Vec<usize>>()) {
match Peekable::new(collection.iter()).last() {
Some(m) => prop_assert_eq!(m, collection.iter().last().unwrap()),
None => prop_assert!(collection.last().is_none())
}
}
#[test]
fn iter_last_peeked(collection in any::<Vec<usize>>()) {
let mut iter = Peekable::new(collection.iter());
let _ = iter.peek();
match iter.last() {
Some(m) => prop_assert_eq!(m, collection.iter().last().unwrap()),
None => prop_assert!(collection.last().is_none())
}
}
#[test]
fn iter_last_peeked_2(collection in any::<Vec<usize>>()) {
let mut iter = Peekable::new(collection.iter());
let _ = iter.peek_2();
match iter.last() {
Some(m) => prop_assert_eq!(m, collection.iter().last().unwrap()),
None => prop_assert!(collection.last().is_none())
}
}
#[test]
fn iter_next_back(collection in any::<Vec<usize>>(), extra_iters in 1..7usize) {
let mut iter = Peekable::new(collection.iter());
let mut iter_spec = collection.iter();
loop {
let res = iter.next_back();
let s_res = iter_spec.next_back();
prop_assert_eq!(res, s_res);
if res.is_none() { break; }
}
for _ in 0..extra_iters {
prop_assert_eq!(iter.next_back(), iter_spec.next_back());
}
}
#[test]
fn iter_next_back_peeked(collection in any::<Vec<usize>>(), extra_iters in 1..7usize) {
let mut iter = Peekable::new(collection.iter());
let mut iter_spec = collection.iter();
let _ = iter.peek();
loop {
let res = iter.next_back();
let s_res = iter_spec.next_back();
prop_assert_eq!(res, s_res);
if res.is_none() { break; }
}
for _ in 0..extra_iters {
prop_assert_eq!(iter.next_back(), iter_spec.next_back(), "Extra iters failure.");
}
}
#[test]
fn iter_next_back_peeked_2(collection in any::<Vec<usize>>(), extra_iters in 1..7usize) {
let mut iter = Peekable::new(collection.iter());
let mut iter_spec = collection.iter();
let _ = iter.peek_2();
loop {
let res = iter.next_back();
let s_res = iter_spec.next_back();
prop_assert_eq!(res, s_res);
if res.is_none() { break; }
}
for _ in 0..extra_iters {
prop_assert_eq!(iter.next_back(), iter_spec.next_back(), "Extra iters failure.");
}
}
#[test]
fn iter_rfind(collection in any::<Vec<usize>>(), extra_iters in 1..7usize) {
let mut iter = Peekable::new(collection.iter());
let mut iter_spec = collection.iter();
loop {
let res = iter.rfind(|x| *x == &0);
let s_res = iter_spec.rfind(|x| *x == &0);
prop_assert_eq!(res, s_res);
if res.is_none() { break; }
}
for _ in 0..extra_iters {
prop_assert_eq!(iter.rfind(|x| *x == &0), iter_spec.rfind(|x| *x == &0), "Extra iters failure.");
}
}
#[test]
fn iter_rfind_peeked(collection in any::<Vec<usize>>(), extra_iters in 1..7usize) {
let mut iter = Peekable::new(collection.iter());
let mut iter_spec = collection.iter();
let _ = iter.peek();
loop {
let res = iter.rfind(|x| *x == &0);
let s_res = iter_spec.rfind(|x| *x == &0);
prop_assert_eq!(res, s_res);
if res.is_none() { break; }
}
for _ in 0..extra_iters {
prop_assert_eq!(iter.rfind(|x| *x == &0), iter_spec.rfind(|x| *x == &0), "Extra iters failure.");
}
}
#[test]
fn iter_rfind_peeked_2(collection in any::<Vec<usize>>(), extra_iters in 1..7usize) {
let mut iter = Peekable::new(collection.iter());
let mut iter_spec = collection.iter();
let _ = iter.peek_2();
loop {
let res = iter.rfind(|x| *x == &0);
let s_res = iter_spec.rfind(|x| *x == &0);
prop_assert_eq!(res, s_res);
if res.is_none() { break; }
}
for _ in 0..extra_iters {
prop_assert_eq!(iter.rfind(|x| *x == &0), iter_spec.rfind(|x| *x == &0), "Extra iters failure.");
}
}
#[test]
fn exact_size_len(collection in any::<Vec<()>>()) {
let peekable = Peekable::new(collection.iter());
let iter = collection.iter();
prop_assert_eq!(iter.len(), peekable.len());
}
#[test]
fn exact_size_len_peeked(collection in any::<Vec<()>>()) {
let mut peekable = Peekable::new(collection.iter());
let iter = collection.iter();
let _ = peekable.peek();
prop_assert_eq!(iter.len(), peekable.len());
}
#[test]
fn exact_size_len_peeked_2(collection in any::<Vec<()>>()) {
let mut peekable = Peekable::new(collection.iter());
let iter = collection.iter();
let _ = peekable.peek_2();
prop_assert_eq!(iter.len(), peekable.len());
}
}
#[test]
fn drain_if_both_full_smoke() {
let mut iter = Peekable::new([1, 2].into_iter());
let peeked = iter.peek();
let Some((a, b)) = peeked.drain_if_both(|a, b| a == &1 && b == &2).drained() else { unreachable!() };
assert_eq!(a, 1);
assert_eq!(b, 2);
assert!(iter.peek_state().is_empty());
assert_eq!(iter.len(), 0);
}
#[test]
fn drain_if_both_missing_elem() {
let mut iter = Peekable::new([1].into_iter());
let peeked = iter.peek();
assert!(!peeked.drain_if_both(|a, b| a == &1 && b == &2).is_drained());
}
#[test]
fn drain_if_both_empty() {
let list: [u8; 0] = [];
let mut iter = Peekable::new(list.into_iter());
let peeked = iter.peek();
assert!(!peeked.drain_if_both(|a, b| a == &1 && b == &2).is_drained());
}
#[test]
fn is_both_full_smoke() {
let mut iter = Peekable::new([1, 2].into_iter());
let mut peeked = iter.peek();
assert!(peeked.is_both(|a, b| a == &1 && b == &2));
assert!(iter.next() == Some(1));
assert!(iter.next() == Some(2));
assert!(iter.next() == None);
}
#[test]
fn is_both_missing_elem() {
let mut iter = Peekable::new([1].into_iter());
let mut peeked = iter.peek();
assert!(!peeked.is_both(|a, b| a == &1 && b == &2));
assert!(iter.next() == Some(1));
assert!(iter.next() == None);
}
}
#[cfg(all(kani, test))]
mod checks {
use kani::proof;
use super::*;
#[proof]
fn next_always_decrements_len() {
let mut iter = Peekable::new([1, 2, 3, 4].into_iter());
let len = iter.len();
iter.next();
kani::assert(iter.len() == len - 1, "Length decrements as iterator is consumed.");
let _ = iter.peek();
kani::assert(iter.len() == len - 1, "Peek must not alter the length.");
let _ = iter.peek_2();
kani::assert(iter.len() == len - 1, "Peek2 must not alter the length.");
iter.next();
kani::assert(iter.len() == len - 2, "Length decrements as iterator is consumed under peek2 state.");
kani::assert(iter.peek_state().only_one(), "Next transitions from peek2 to peek");
iter.next();
kani::assert(iter.len() == len - 3, "Length decrements as iterator is consumed under peek state.");
kani::assert(iter.peek_state().is_empty(), "Next transitions from peek to empty");
}
#[proof]
fn take_approaches_empty() {
let mut iter = Peekable::new([1, 2, 3, 4].into_iter());
let _ = iter.peek_2();
kani::assert(iter.peek_state().is_full(), "fill ensures the state is full.");
kani::assert(iter.peeked.take().is_some(), "`take` always returns Some when state is non-empty.");
kani::assert(iter.peek_state().only_one(), "`take` transitions full to only one");
kani::assert(iter.peeked.take().is_some(), "`take` always returns Some when state is non-empty.");
kani::assert(iter.peek_state().is_empty(), "`take` transitions only one to empty`");
kani::assert(iter.peeked.take().is_none(), "`take` while empty always results in None");
kani::assert(iter.peek_state().is_empty(), "`take` transitions empty to empty");
}
#[proof]
fn fill() {
let mut iter = Peekable::new([1, 2, 3, 4].into_iter());
let _ = iter.peek_2();
kani::assert(iter.peek_state().is_full(), "peek_2's usage of `fill` ensures the state is full.");
}
#[proof]
fn fill_from_once() {
let mut iter = Peekable::new([1, 2, 3, 4].into_iter());
let _ = iter.peek();
kani::assert(iter.peek_state().only_one(), "one transition without any take ensures the state is Once.");
let _ = iter.peek_2();
kani::assert(iter.peek_state().is_full(), "peek_2's usage of `fill` ensures the state is full.");
}
#[proof]
fn transition() {
let mut iter = Peekable::new([1, 2, 3, 4].into_iter());
let _ = iter.peek();
kani::assert(iter.peek_state().only_one(), "one transition without any take ensures the state is Once.");
let mut peek = iter.peek();
let _ = peek.peek();
kani::assert(iter.peek_state().is_full(), "two transitions without any take ensures the state is full.");
}
#[proof]
fn take_next_if() {
let mut iter = Peekable::new([1, 2, 3, 4].into_iter());
let mut peeked = iter.peek();
let item = peeked.take_next_if(|elem| elem == &2);
kani::assert(item == Some(2), "take_next_if returns elem given to predicate");
kani::assert(iter.next() == Some(1), "iter behaves normally with second elem removed");
kani::assert(iter.next() == Some(3), "iter behaves normally with second elem removed");
kani::assert(iter.next() == Some(4), "iter behaves normally with second elem removed");
kani::assert(iter.next().is_none(), "iter behaves normally with second elem removed");
kani::assert(iter.next().is_none(), "iter behaves normally with second elem removed");
}
#[proof]
fn take_next_if_pred_false() {
let mut iter = Peekable::new([1, 2, 3, 4].into_iter());
let mut peeked = iter.peek();
let item = peeked.take_next_if(|elem| elem == &7);
kani::assert(item.is_none(), "take_next_if returns None when predicate not met");
kani::assert(iter.next() == Some(1), "iter behaves normally with predicate failed");
kani::assert(iter.next() == Some(2), "iter behaves normally with predicate failed");
kani::assert(iter.next() == Some(3), "iter behaves normally with predicate failed");
kani::assert(iter.next() == Some(4), "iter behaves normally with predicate failed");
kani::assert(iter.next().is_none(), "iter behaves normally with predicate failed");
kani::assert(iter.next().is_none(), "iter behaves normally with predicate failed");
}
#[proof]
fn take_next_if_one_elem() {
let mut iter = Peekable::new([1].into_iter());
let mut peeked = iter.peek();
let item = peeked.take_next_if(|_| unreachable!());
kani::assert(item.is_none(), "take_next_if returns None when predicate not met (which is always w/ empty)");
kani::assert(iter.next() == Some(1), "iter behaves normally with predicate failed");
kani::assert(iter.next().is_none(), "iter behaves normally with predicate failed");
kani::assert(iter.next().is_none(), "iter behaves normally with predicate failed");
}
#[proof]
fn take_next_if_empty() {
let list: [u8; 0] = [];
let mut iter = Peekable::new(list.into_iter());
let mut peeked = iter.peek();
let item = peeked.take_next_if(|_| unreachable!());
kani::assert(item.is_none(), "take_next_if returns None when predicate not met (which is always w/ empty)");
kani::assert(iter.next().is_none(), "iter behaves normally with predicate failed");
kani::assert(iter.next().is_none(), "iter behaves normally with predicate failed");
}
#[proof]
fn drain_if_both_full() {
let mut iter = Peekable::new([1, 2].into_iter());
let peeked = iter.peek();
let Some((a, b)) = peeked.drain_if_both(|a, b| a == &1 && b == &2).drained() else { unreachable!() };
kani::assert(a == 1, "drained elements must maintain order");
kani::assert(b == 2, "drained elements must maintain order");
kani::assert(iter.peek_state().is_empty(), "successfully draining must empty the peek state.");
kani::assert(iter.len() == 0, "successfully draining both elements must leave the iterator empty.");
}
#[proof]
fn drain_if_both_missing_elem() {
let mut iter = Peekable::new([1].into_iter());
let peeked = iter.peek();
kani::assert(
!peeked.drain_if_both(|a, b| a == &1 && b == &2).is_drained(),
"drain_if_both when missing element is idempotent"
);
kani::assert(iter.next() == Some(1), "iterator is unchanged");
kani::assert(iter.next().is_none(), "iterator terminated");
}
#[proof]
fn drain_if_both_empty() {
let list: [u8; 0] = [];
let mut iter = Peekable::new(list.into_iter());
let peeked = iter.peek();
kani::assert(
!peeked.drain_if_both(|a, b| a == &1 && b == &2).is_drained(),
"drain_if_both on empty iterator is idempotent"
);
kani::assert(iter.len() == 0, "an empty iterator remains an empty iterator.");
}
#[proof]
fn drain_if_both_idempotence() {
let mut iter = Peekable::new([1, 2].into_iter());
let peeked = iter.peek();
kani::assert(
!peeked.drain_if_both(|a, b| a == &3 && b == &4).is_drained(),
"drain_if_both on failing predicate is idempotent"
);
kani::assert(iter.next() == Some(1), "iterator is unchanged");
kani::assert(iter.next() == Some(2), "iterator is unchanged");
kani::assert(iter.next().is_none(), "iterator terminates");
}
#[proof]
fn is_both_success() {
let mut iter = Peekable::new([1, 2].into_iter());
let mut peeked = iter.peek();
kani::assert(peeked.is_both(|a, b| a == &1 && b == &2), "is both respects the predicate");
kani::assert(iter.next() == Some(1), "iterator is unchanged");
kani::assert(iter.next() == Some(2), "iterator is unchanged");
kani::assert(iter.next().is_none(), "iterator terminates");
}
#[proof]
fn is_both_missing_elem() {
let mut iter = Peekable::new([1].into_iter());
let mut peeked = iter.peek();
kani::assert(!peeked.is_both(|a, b| a == &1 && b == &2), "if cannot fill both, always is false");
kani::assert(iter.next() == Some(1), "iterator is unchanged");
kani::assert(iter.next().is_none(), "iterator terminates");
}
#[proof]
fn is_both_empty() {
let list: [u8; 0] = [];
let mut iter = Peekable::new(list.into_iter());
let mut peeked = iter.peek();
kani::assert(!peeked.is_both(|a, b| a == &1 && b == &2), "if empty, always is false");
kani::assert(iter.next().is_none(), "iterator is unchanged and terminates");
}
}