use core::{
fmt::{self, Debug, Display, Formatter},
iter::FusedIterator,
mem,
};
#[cfg(feature = "nightly")]
use core::{iter::TrustedLen, ops::Try};
use crate::{
join::{Join, Joinable},
separators::NoSeparator,
};
#[derive(Debug, Clone, Eq, PartialEq)]
#[repr(transparent)]
pub struct CloneIterator<I>(I);
impl<I: Iterator> IntoIterator for CloneIterator<I> {
type IntoIter = I;
type Item = I::Item;
fn into_iter(self) -> Self::IntoIter {
self.0
}
}
impl<'a, I: Iterator + Clone> IntoIterator for &'a CloneIterator<I> {
type IntoIter = I;
type Item = I::Item;
fn into_iter(self) -> Self::IntoIter {
self.0.clone()
}
}
pub trait JoinableIterator: Iterator + Sized {
fn join_with<S>(self, sep: S) -> Join<CloneIterator<Self>, S>
where
Self: Clone,
{
CloneIterator(self).join_with(sep)
}
fn join_concat(self) -> Join<CloneIterator<Self>, NoSeparator>
where
Self: Clone,
{
self.join_with(NoSeparator)
}
fn iter_join_with<S>(self, sep: S) -> JoinIter<Self, S> {
JoinIter::new(self, sep)
}
}
impl<T: Iterator> JoinableIterator for T {}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum JoinItem<T, S> {
Element(T),
Separator(S),
}
impl<T, S> JoinItem<T, S> {
pub fn into<R>(self) -> R
where
T: Into<R>,
S: Into<R>,
{
match self {
JoinItem::Element(el) => el.into(),
JoinItem::Separator(sep) => sep.into(),
}
}
}
impl<R, T: AsRef<R>, S: AsRef<R>> AsRef<R> for JoinItem<T, S> {
fn as_ref(&self) -> &R {
match self {
JoinItem::Element(el) => el.as_ref(),
JoinItem::Separator(sep) => sep.as_ref(),
}
}
}
impl<R, T: AsMut<R>, S: AsMut<R>> AsMut<R> for JoinItem<T, S> {
fn as_mut(&mut self) -> &mut R {
match self {
JoinItem::Element(el) => el.as_mut(),
JoinItem::Separator(sep) => sep.as_mut(),
}
}
}
impl<T: Display, S: Display> Display for JoinItem<T, S> {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
match self {
JoinItem::Element(el) => el.fmt(f),
JoinItem::Separator(sep) => sep.fmt(f),
}
}
}
#[derive(Debug, Clone, Copy)]
enum JoinIterState<T> {
Initial,
Separator,
Element(T),
}
#[must_use]
pub struct JoinIter<Iter: Iterator, Sep> {
iter: Iter,
sep: Sep,
state: JoinIterState<Iter::Item>,
}
impl<I: Iterator, S> JoinIter<I, S> {
fn new(iter: I, sep: S) -> Self {
JoinIter {
iter,
sep,
state: JoinIterState::Initial,
}
}
}
impl<I: Iterator, S> JoinIter<I, S> {
#[inline]
pub fn is_sep_next(&self) -> bool {
matches!(self.state, JoinIterState::Separator)
}
#[inline]
pub fn sep(&self) -> &S {
&self.sep
}
}
impl<I: Debug + Iterator, S: Debug> Debug for JoinIter<I, S>
where
I::Item: Debug,
{
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
f.debug_struct("JoinIter")
.field("iter", &self.iter)
.field("sep", &self.sep)
.field("state", &self.state)
.finish()
}
}
impl<I: Clone + Iterator, S: Clone> Clone for JoinIter<I, S>
where
I::Item: Clone, {
fn clone(&self) -> Self {
JoinIter {
iter: self.iter.clone(),
sep: self.sep.clone(),
state: self.state.clone(),
}
}
fn clone_from(&mut self, source: &Self) {
self.iter.clone_from(&source.iter);
self.sep.clone_from(&source.sep);
self.state.clone_from(&source.state);
}
}
#[inline]
fn join_size<T>(iter_size: usize, state: &JoinIterState<T>) -> Option<usize> {
match *state {
JoinIterState::Initial => match iter_size {
0 => Some(0),
_ => (iter_size - 1).checked_mul(2)?.checked_add(1),
},
JoinIterState::Separator => iter_size.checked_mul(2),
JoinIterState::Element(..) => iter_size.checked_mul(2)?.checked_add(1),
}
}
impl<I: Iterator, S: Clone> Iterator for JoinIter<I, S> {
type Item = JoinItem<I::Item, S>;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
match mem::replace(&mut self.state, JoinIterState::Separator) {
JoinIterState::Initial => self.iter.next().map(JoinItem::Element),
JoinIterState::Separator => self.iter.next().map(|element| {
self.state = JoinIterState::Element(element);
JoinItem::Separator(self.sep.clone())
}),
JoinIterState::Element(element) => Some(JoinItem::Element(element)),
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
let (min, max) = self.iter.size_hint();
let min = join_size(min, &self.state).unwrap_or(core::usize::MAX);
let max = max.and_then(|max| join_size(max, &self.state));
(min, max)
}
fn count(self) -> usize
where
Self: Sized,
{
match self.state {
JoinIterState::Initial => (self.iter.count() * 2).saturating_sub(1),
JoinIterState::Separator => self.iter.count() * 2,
JoinIterState::Element(_) => self.iter.count() * 2 + 1,
}
}
fn last(self) -> Option<Self::Item>
where
Self: Sized,
{
self.iter
.last()
.or(match self.state {
JoinIterState::Initial | JoinIterState::Separator => None,
JoinIterState::Element(item) => Some(item),
})
.map(JoinItem::Element)
}
fn fold<B, F>(mut self, init: B, mut func: F) -> B
where
F: FnMut(B, Self::Item) -> B,
{
let accum = match self.state {
JoinIterState::Initial => match self.iter.next() {
None => return init,
Some(element) => func(init, JoinItem::Element(element)),
},
JoinIterState::Separator => init,
JoinIterState::Element(element) => func(init, JoinItem::Element(element)),
};
self.iter.fold(accum, move |accum, element| {
let accum = func(accum, JoinItem::Separator(self.sep.clone()));
func(accum, JoinItem::Element(element))
})
}
#[cfg(feature = "nightly")]
fn try_fold<B, F, R>(&mut self, init: B, mut func: F) -> R
where
Self: Sized,
F: FnMut(B, Self::Item) -> R,
R: Try<Output = B>,
{
use core::ops::ControlFlow;
let accum = match mem::replace(&mut self.state, JoinIterState::Separator) {
JoinIterState::Initial => match self.iter.next() {
None => return R::from_output(init),
Some(element) => func(init, JoinItem::Element(element))?,
},
JoinIterState::Separator => init,
JoinIterState::Element(element) => func(init, JoinItem::Element(element))?,
};
self.iter.try_fold(accum, |accum, element| {
match func(accum, JoinItem::Separator(self.sep.clone())).branch() {
ControlFlow::Break(err) => {
self.state = JoinIterState::Element(element);
R::from_residual(err)
}
ControlFlow::Continue(accum) => func(accum, JoinItem::Element(element)),
}
})
}
}
impl<I: FusedIterator, S: Clone> FusedIterator for JoinIter<I, S> {}
#[cfg(feature = "nightly")]
unsafe impl<I: TrustedLen, S: Clone> TrustedLen for JoinIter<I, S> {}
#[cfg(test)]
mod tests {
use super::JoinItem::*;
use super::JoinableIterator;
#[test]
fn empty_iter() {
let mut join_iter = (0..0).iter_join_with(", ");
assert_eq!(join_iter.next(), None);
assert_eq!(join_iter.next(), None);
}
#[test]
fn single() {
let mut join_iter = (0..1).iter_join_with(", ");
assert_eq!(join_iter.next(), Some(Element(0)));
assert_eq!(join_iter.next(), None);
assert_eq!(join_iter.next(), None);
}
#[test]
fn few() {
let mut join_iter = (0..3).iter_join_with(", ");
assert_eq!(join_iter.next(), Some(Element(0)));
assert_eq!(join_iter.next(), Some(Separator(", ")));
assert_eq!(join_iter.next(), Some(Element(1)));
assert_eq!(join_iter.next(), Some(Separator(", ")));
assert_eq!(join_iter.next(), Some(Element(2)));
assert_eq!(join_iter.next(), None);
assert_eq!(join_iter.next(), None);
}
#[test]
fn regular_size_hint() {
let mut join_iter = (0..10).iter_join_with(", ");
for size in (0..=19).rev() {
assert_eq!(join_iter.size_hint(), (size, Some(size)));
join_iter.next();
}
assert_eq!(join_iter.size_hint(), (0, Some(0)));
join_iter.next();
assert_eq!(join_iter.size_hint(), (0, Some(0)));
}
#[test]
fn large_size_hint() {
let join_iter = (0..usize::max_value() - 10).iter_join_with(", ");
assert_eq!(join_iter.size_hint(), (usize::max_value(), None));
}
#[test]
fn threshold_size_hint() {
use core::usize::MAX as usize_max;
let usize_threshold = (usize_max / 2) + 1;
let mut join_iter = (0..usize_threshold + 1).iter_join_with(", ");
assert_eq!(join_iter.size_hint(), (usize_max, None));
join_iter.next();
assert_eq!(join_iter.size_hint(), (usize_max, None));
join_iter.next();
assert_eq!(join_iter.size_hint(), (usize_max, Some(usize_max)));
join_iter.next();
assert_eq!(join_iter.size_hint(), (usize_max - 1, Some(usize_max - 1)));
}
#[test]
fn partial_iteration() {
use std::vec::Vec;
let mut join_iter = (0..3).iter_join_with(' ');
join_iter.next();
let rest: Vec<_> = join_iter.collect();
assert_eq!(
rest,
[Separator(' '), Element(1), Separator(' '), Element(2),]
);
}
#[test]
fn fold() {
let content = [1, 2, 3];
let join_iter = content.iter().iter_join_with(4);
let sum = join_iter.fold(0, |accum, next| match next {
Element(el) => accum + el,
Separator(sep) => accum + sep,
});
assert_eq!(sum, 14);
}
#[test]
fn partial_fold() {
let content = [1, 2, 3, 4];
let mut join_iter = content.iter().iter_join_with(1);
join_iter.next();
join_iter.next();
join_iter.next();
let sum = join_iter.fold(0, |accum, next| match next {
Element(el) => accum + el,
Separator(sep) => accum + sep,
});
assert_eq!(sum, 9);
}
#[test]
fn try_fold() {
let content = [1, 2, 0, 3];
let mut join_iter = content.iter().iter_join_with(1);
let result = join_iter.try_fold(0, |accum, next| match next {
Separator(sep) => Ok(accum + sep),
Element(el) if *el == 0 => Err(accum),
Element(el) => Ok(accum + el),
});
assert_eq!(result, Err(5));
}
#[test]
fn partial_try_fold() {
let content = [1, 2, 3];
let mut join_iter = content.iter().iter_join_with(1);
let _ = join_iter.try_fold(1, |_, next| match next {
Element(_) => Some(1),
Separator(_) => None,
});
assert_eq!(join_iter.count(), 3);
}
#[test]
fn last_empty() {
let content: [i32; 0] = [];
let join_iter = content.iter().iter_join_with(0);
assert_eq!(join_iter.last(), None);
}
#[test]
fn last_only() {
let content = [1];
let join_iter = content.iter().iter_join_with(0);
assert_eq!(join_iter.last(), Some(Element(&1)));
}
#[test]
fn last_initial() {
let content = [1, 2, 3];
let join_iter = content.iter().iter_join_with(0);
assert_eq!(join_iter.last(), Some(Element(&3)));
}
#[test]
fn last_sep() {
let content = [1, 2, 3];
let mut join_iter = content.iter().iter_join_with(0);
join_iter.next().unwrap();
assert_eq!(join_iter.last(), Some(Element(&3)));
}
#[test]
fn last_element() {
let content = [1, 2, 3];
let mut join_iter = content.iter().iter_join_with(0);
join_iter.next().unwrap();
join_iter.next().unwrap();
assert_eq!(join_iter.last(), Some(Element(&3)));
}
#[test]
fn last_sep_2() {
let content = [1, 2];
let mut join_iter = content.iter().iter_join_with(0);
join_iter.next().unwrap();
assert_eq!(join_iter.last(), Some(Element(&2)));
}
#[test]
fn last_element_2() {
let content = [1, 2];
let mut join_iter = content.iter().iter_join_with(0);
join_iter.next().unwrap();
join_iter.next().unwrap();
assert_eq!(join_iter.last(), Some(Element(&2)));
}
#[test]
fn last_emptied() {
let content = [1, 2];
let mut join_iter = content.iter().iter_join_with(0);
join_iter.next().unwrap();
join_iter.next().unwrap();
join_iter.next().unwrap();
assert_eq!(join_iter.last(), None);
}
}