1#![cfg_attr(not(test), no_std)]
20#![deny(warnings)]
21#![warn(
22 clippy::all,
23 clippy::missing_docs_in_private_items,
24 clippy::nursery,
25 clippy::pedantic,
26 clippy::restriction,
27 clippy::cargo,
28 missing_docs,
29 rustdoc::all
30)]
31#![allow(
32 clippy::blanket_clippy_restriction_lints,
33 clippy::cognitive_complexity,
34 clippy::expect_used,
35 clippy::implicit_return,
36 clippy::inline_always,
37 clippy::needless_borrowed_reference,
38 clippy::panic,
39 clippy::question_mark_used,
40 clippy::separated_literal_suffix,
41 clippy::string_add,
42 clippy::unwrap_used
43)]
44
45use ::core::{cell::Cell, convert::Infallible, marker::PhantomData};
46use reiterator::{Reiterate, Reiterator};
47
48#[cfg(test)]
49mod test;
50
51pub trait Flatten {
53 type Flattened;
55 #[must_use]
57 fn flatten(self) -> Self::Flattened;
58}
59
60impl Flatten for () {
61 type Flattened = Self;
62 #[inline(always)]
63 #[must_use]
64 fn flatten(self) -> Self::Flattened {}
65}
66
67breadth_first_zip_macros::implement_flatten!();
68
69#[derive(Clone, Debug, Default, Eq, Ord, PartialEq, PartialOrd)]
71pub struct BaseCase(Cell<bool>);
72
73mod sealed {
75 pub trait BreadthFirst {}
77 impl BreadthFirst for super::BaseCase {}
78 impl<'item, Head: Iterator, Tail: super::BreadthFirst<'item>> BreadthFirst
79 for super::BreadthFirstZipped<'item, Head, Tail>
80 {
81 }
82}
83
84pub trait BreadthFirst<'item>: sealed::BreadthFirst {
86 const DEPTH: usize;
88 type Advance: Flatten;
90 #[must_use]
92 fn next(&'item self, index_sum: usize) -> Option<Self::Advance>;
93 fn rewind(&self);
95}
96
97impl<'item> BreadthFirst<'item> for BaseCase {
98 const DEPTH: usize = 0;
99 type Advance = ();
100 #[inline(always)]
101 #[must_use]
102 fn next(&self, index_sum: usize) -> Option<Self::Advance> {
103 (index_sum == 0 && self.0.get()).then(|| {
104 self.0.set(false);
105 })
106 }
107 #[inline(always)]
108 fn rewind(&self) {
109 self.0.set(true);
110 }
111}
112
113pub struct BreadthFirstZipped<'item, Head: Iterator, Tail: BreadthFirst<'item>> {
115 iter: Reiterator<Head>,
117 tail: Tail,
119 lifetime: PhantomData<&'item Infallible>,
121}
122
123impl<'item, Head: Iterator, Tail: BreadthFirst<'item>> BreadthFirstZipped<'item, Head, Tail> {
124 #[inline(always)]
126 pub fn new(head: Head, tail: Tail) -> Self {
127 Self {
128 iter: head.reiterate(),
129 tail,
130 lifetime: PhantomData,
131 }
132 }
133}
134
135impl<'item, Head: Iterator, Tail: BreadthFirst<'item>> BreadthFirst<'item>
136 for BreadthFirstZipped<'item, Head, Tail>
137where
138 Head::Item: 'item,
139 (&'item Head::Item, Tail::Advance): Flatten,
140{
141 const DEPTH: usize = Tail::DEPTH + 1;
142 type Advance = (&'item Head::Item, Tail::Advance);
143 #[inline(always)]
144 #[must_use]
145 fn next(&'item self, index_sum: usize) -> Option<Self::Advance> {
146 loop {
147 if let Some(tail) = self
148 .tail
149 .next(index_sum.checked_sub(self.iter.index.get())?)
150 {
151 return self.iter.get().map(|indexed| (indexed.value, tail));
152 }
153 (self.iter.index.get() < index_sum).then(|| self.iter.next())??; self.tail.rewind();
155 }
156 }
157 #[inline(always)]
158 fn rewind(&self) {
159 self.iter.restart();
160 self.tail.rewind();
161 }
162}
163
164#[derive(Clone, Debug, Default, Eq, Ord, PartialEq, PartialOrd)]
166pub struct BreadthFirstManager<'item, Tail: BreadthFirst<'item>> {
167 tail: Tail,
169 index_sum: Cell<usize>,
171 lifetime: PhantomData<&'item Infallible>,
173}
174
175impl<'item, Tail: BreadthFirst<'item>> BreadthFirstManager<'item, Tail> {
176 #[inline(always)]
178 #[must_use]
179 pub const fn new(tail: Tail) -> Self {
180 Self {
181 tail,
182 index_sum: Cell::new(0),
183 lifetime: PhantomData,
184 }
185 }
186 #[allow(clippy::should_implement_trait)]
189 #[inline(always)]
190 #[must_use]
191 pub fn next(&'item self) -> Option<<Tail::Advance as Flatten>::Flattened> {
192 self.tail
193 .next(self.index_sum.get())
194 .map_or_else(
195 || {
196 self.index_sum.set(self.index_sum.get().checked_add(1)?);
197 self.tail.rewind();
198 self.tail.next(self.index_sum.get())
199 },
200 Some,
201 )
202 .map(Flatten::flatten)
203 }
204}
205
206pub trait BreadthFirstZip<'item> {
208 type Nested: BreadthFirst<'item>;
210 fn breadth_first(self) -> BreadthFirstManager<'item, Self::Nested>;
212 fn unflatten(self) -> Self::Nested;
216}
217
218impl<'item> BreadthFirstZip<'item> for () {
219 type Nested = BaseCase;
220 #[inline(always)]
221 fn breadth_first(self) -> BreadthFirstManager<'item, Self::Nested> {
222 BreadthFirstManager::new(self.unflatten())
223 }
224 #[inline(always)]
225 fn unflatten(self) -> Self::Nested {
226 BaseCase(Cell::new(true))
227 }
228}
229
230breadth_first_zip_macros::implement!();