use core::fmt::*;
use crate::once::Once;
mod r#macro;
pub(crate) mod types {
#[allow(unused)]
use super::*;
#[derive(Clone, Copy)]
pub struct Concat<I> {
pub(super) iter: I,
}
pub type ConcatOnce<I> = Concat<Once<I>>;
#[derive(Clone, Copy)]
pub struct ConcatMap<I, F> {
pub(super) iter: I,
pub(super) map: F,
}
pub type ConcatMapOnce<I, F> = ConcatMap<Once<I>, F>;
#[derive(Clone, Copy)]
pub struct ConcatTuple<T>(pub(super) T);
}
use types::*;
pub fn concat<I>(iter: I) -> Concat<I::IntoIter>
where
I: IntoIterator,
I::IntoIter: Clone,
{
iter.into()
}
pub fn concat_once<I: IntoIterator>(iter: I) -> ConcatOnce<I::IntoIter> {
Concat { iter: Once::new(iter.into_iter()) }
}
pub fn concat_map<I, R, F>(iter: I, f: F) -> ConcatMap<I::IntoIter, F>
where
I: IntoIterator,
I::IntoIter: Clone,
F: Fn(I::Item) -> R,
{
ConcatMap { iter: iter.into_iter(), map: f }
}
pub fn concat_map_once<I, R, F>(iter: I, f: F) -> ConcatMapOnce<I::IntoIter, F>
where
I: IntoIterator,
F: Fn(I::Item) -> R,
{
ConcatMap { iter: Once::new(iter.into_iter()), map: f }
}
pub fn concat_tuple<T>(tuple: T) -> ConcatTuple<T> {
ConcatTuple(tuple)
}
impl<I> From<I> for Concat<I::IntoIter>
where
I: IntoIterator,
I::IntoIter: Clone,
{
fn from(iter: I) -> Self {
Self { iter: iter.into_iter() }
}
}
impl<I> Debug for Concat<I>
where
I: Iterator + Clone,
I::Item: Debug,
{
fn fmt(&self, f: &mut Formatter) -> Result {
for item in self.iter.clone() {
write!(f, "{:?}", item)?;
}
Ok(())
}
}
impl<I> Display for Concat<I>
where
I: Iterator + Clone,
I::Item: Display,
{
fn fmt(&self, f: &mut Formatter) -> Result {
for item in self.iter.clone() {
write!(f, "{}", item)?;
}
Ok(())
}
}
impl<I, F, R> Debug for ConcatMap<I, F>
where
I: Iterator + Clone,
F: Fn(I::Item) -> R,
R: Debug,
{
fn fmt(&self, f: &mut Formatter) -> Result {
for item in self.iter.clone() {
write!(f, "{:?}", (self.map)(item))?;
}
Ok(())
}
}
impl<I, F, R> Display for ConcatMap<I, F>
where
I: Iterator + Clone,
F: Fn(I::Item) -> R,
R: Display,
{
fn fmt(&self, f: &mut Formatter) -> Result {
for item in self.iter.clone() {
write!(f, "{}", (self.map)(item))?;
}
Ok(())
}
}
impl<I> Debug for ConcatOnce<I>
where
I: Iterator,
I::Item: Debug,
{
fn fmt(&self, f: &mut Formatter) -> Result {
if let Some(iter) = self.iter.take() {
for item in iter {
write!(f, "{:?}", item)?;
}
}
Ok(())
}
}
impl<I> Display for ConcatOnce<I>
where
I: Iterator,
I::Item: Display,
{
fn fmt(&self, f: &mut Formatter) -> Result {
if let Some(iter) = self.iter.take() {
for item in iter {
write!(f, "{}", item)?;
}
}
Ok(())
}
}
impl<I, F, R> Debug for ConcatMapOnce<I, F>
where
I: Iterator + Clone,
F: Fn(I::Item) -> R,
R: Debug,
{
fn fmt(&self, f: &mut Formatter) -> Result {
if let Some(iter) = self.iter.take() {
for item in iter {
write!(f, "{:?}", (self.map)(item))?;
}
}
Ok(())
}
}
impl<I, F, R> Display for ConcatMapOnce<I, F>
where
I: Iterator + Clone,
F: Fn(I::Item) -> R,
R: Display,
{
fn fmt(&self, f: &mut Formatter) -> Result {
if let Some(iter) = self.iter.take() {
for item in iter {
write!(f, "{}", (self.map)(item))?;
}
}
Ok(())
}
}
impl Debug for ConcatTuple<()> {
#[inline]
fn fmt(&self, _: &mut Formatter) -> Result {
Ok(())
}
}
impl Display for ConcatTuple<()> {
#[inline]
fn fmt(&self, _: &mut Formatter) -> Result {
Ok(())
}
}
macro_rules! impl_tuple {
() => {};
($($x:ident),+) => {
impl<$($x),+> Debug for ConcatTuple<($($x,)+)>
where
$($x: Debug),+
{
fn fmt(&self, f: &mut Formatter) -> Result {
#[allow(non_snake_case)]
let ($($x,)+) = &self.0;
write!(
f,
core::concat!($("{", core::stringify!($x), ":?}",)+),
$($x = $x),+
)
}
}
impl<$($x),+> Display for ConcatTuple<($($x,)+)>
where
$($x: Display),+
{
fn fmt(&self, f: &mut Formatter) -> Result {
#[allow(non_snake_case)]
let ($($x,)+) = &self.0;
write!(
f,
core::concat!($("{", core::stringify!($x), "}",)+),
$($x = $x),+
)
}
}
peel!(impl_tuple: $($x),+);
};
}
impl_tuple!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11);
#[cfg(test)]
mod tests {
use std::{
iter,
rc::{Rc, Weak},
};
use super::*;
#[test]
fn concat_tuple() {
macro_rules! test {
(@ $($all:ident),+) => {{
let expected = core::concat!($(core::stringify!($all)),+);
let value = crate::concat!($(core::stringify!($all)),+);
assert_eq!(value.to_string(), expected);
}};
($a:ident) => {
test!(@ $a);
};
($a:ident $(, $rest:ident)+) => {
test!($($rest),+);
test!(@ $a, $($rest),+);
};
}
#[rustfmt::skip]
test!(
A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11,
B0, B1, B2, B3, B4, B5, B6, B7, B8, B9, B10, B11
);
}
#[test]
fn concat_once_cycle() {
let rc: Rc<ConcatOnce<iter::FromFn<_>>> = Rc::new_cyclic(|rc| {
let rc = Weak::clone(rc) as Weak<dyn Display>;
let mut ran = false;
let iter = iter::from_fn(move || {
if ran {
return None;
}
ran = true;
let rc = rc.upgrade().expect("`Rc` should be initialized");
Some(format!("X{rc}"))
});
concat_once(iter)
});
assert_eq!(rc.to_string(), "X");
}
}