use core::num::NonZero;
use crate::{accum::Finished, error::FailedStrategy, side::Side};
#[derive(Debug)]
pub struct Apply<I, S> {
iter: I,
strategy: S,
}
impl<I: DoubleEndedIterator, S: Iterator<Item = Side>> Apply<I, S> {
#[inline]
pub(crate) fn new(iter: I, strategy: S) -> Apply<I, S> {
Apply { iter, strategy }
}
}
impl<I: DoubleEndedIterator, S: Iterator<Item = Side>> Iterator for Apply<I, S> {
type Item = (Side, I::Item);
#[inline]
fn next(&mut self) -> Option<(Side, I::Item)> {
match self.strategy.next().expect("strategies should be infinite") {
Side::Forward => self.iter.next().map(|next| (Side::Forward, next)),
Side::Backward => self
.iter
.next_back()
.map(|next_back| (Side::Backward, next_back)),
}
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
self.iter.size_hint()
}
}
#[derive(Clone, Debug)]
pub struct Indices<I> {
iter: I,
forward: isize,
backward: isize,
prev: Side,
}
impl<I> Indices<I> {
pub(crate) fn new(iter: I) -> Indices<I> {
Indices {
iter,
forward: -1,
backward: 0,
prev: Side::Forward,
}
}
#[inline]
pub fn into_error<'a, T, S: ?Sized, V>(
self,
accum: Finished<'a, T>,
strategy: &'a S,
cause: V,
) -> FailedStrategy<'a, T, S, V> {
FailedStrategy {
side: self.prev,
forward: (self.forward + 1).unsigned_abs(),
backward: accum.len() - self.backward.unsigned_abs(),
accum,
strategy,
cause,
}
}
}
impl<I: Iterator<Item = Side>> Iterator for Indices<I> {
type Item = isize;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
self.prev = self.iter.next().expect("strategies should be infinite");
match self.prev {
Side::Forward => {
self.forward += 1;
Some(self.forward)
}
Side::Backward => {
self.backward -= 1;
Some(self.backward)
}
}
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
(isize::MAX.unsigned_abs(), Some(usize::MAX))
}
}
#[derive(Clone, Debug)]
pub struct Alternating {
curr: Side,
left: usize,
period: NonZero<usize>,
}
impl Alternating {
pub(crate) fn new(start: Side, period: NonZero<usize>) -> Alternating {
Alternating {
curr: start,
left: period.get(),
period,
}
}
}
impl Iterator for Alternating {
type Item = Side;
#[inline]
fn next(&mut self) -> Option<Side> {
if self.left > 0 {
self.left -= 1;
Some(self.curr)
} else {
self.left = self.period.get() - 1;
self.curr = self.curr.swap();
Some(self.curr)
}
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
(usize::MAX, None)
}
}
#[derive(Clone, Debug)]
pub struct Todo;
impl Iterator for Todo {
type Item = Side;
#[inline]
fn next(&mut self) -> Option<Side> {
unimplemented!()
}
}
#[cfg(any(doc, feature = "rand"))]
#[cfg_attr(feature = "nightly", doc(cfg(feature = "rand")))]
mod rand {
use crate::side::Side;
#[derive(Debug)]
pub struct Randomly<R> {
rng: R,
forward_prob: f64,
}
impl<#[cfg(feature = "rand")] R: rand::SeedableRng, #[cfg(not(feature = "rand"))] R> Randomly<R> {
#[inline]
pub(crate) fn new(
#[cfg(feature = "rand")] seed: R::Seed,
#[cfg(not(feature = "rand"))] seed: (),
forward_prob: f64,
) -> Randomly<R> {
#[cfg(feature = "rand")]
{
Randomly {
rng: R::from_seed(seed),
forward_prob,
}
}
#[cfg(not(feature = "rand"))]
{
unimplemented!()
}
}
}
impl<#[cfg(feature = "rand")] R: rand::RngCore, #[cfg(not(feature = "rand"))] R> Iterator
for Randomly<R>
{
type Item = Side;
#[inline]
fn next(&mut self) -> Option<Side> {
#[cfg(feature = "rand")]
{
if rand::Rng::random_bool(&mut self.rng, self.forward_prob) {
Some(Side::Forward)
} else {
Some(Side::Backward)
}
}
#[cfg(not(feature = "rand"))]
{
unimplemented!()
}
}
}
}
#[cfg(any(doc, feature = "rand"))]
#[cfg_attr(feature = "nightly", doc(cfg(feature = "rand")))]
pub use self::rand::Randomly;