1#![warn(missing_docs)]
15#![warn(missing_debug_implementations)]
16#![deny(unsafe_code)]
17#![cfg_attr(not(any(feature = "std", test, doc)), no_std)]
18
19#[cfg(feature = "alloc")]
20extern crate alloc;
21
22#[cfg(feature = "alloc")]
23use alloc::{
24 collections::{LinkedList, VecDeque},
25 string::String,
26 vec::Vec,
27};
28use core::fmt;
29
30pub mod prelude {
35 pub use crate::{Contract, Instruction, Operation, StackingIteratorExt};
36}
37
38#[derive(Copy, Clone, PartialEq, Eq, Hash)]
42pub enum Instruction<T> {
43 Mutate(Operation<T>),
45
46 Yield,
48}
49impl<T> Instruction<T> {
50 #[allow(non_upper_case_globals)]
55 pub const Pop: Instruction<T> = Instruction::Mutate(Operation::Pop);
56
57 #[allow(non_snake_case)]
62 pub const fn Push(val: T) -> Instruction<T> {
63 Instruction::Mutate(Operation::Push(val))
64 }
65
66 #[inline]
78 pub fn into_operation(self) -> Option<Operation<T>> {
79 match self {
80 Instruction::Mutate(operation) => Some(operation),
81 Instruction::Yield => None,
82 }
83 }
84
85 #[inline]
97 pub fn as_operation(&self) -> Option<&Operation<T>> {
98 match self {
99 Instruction::Mutate(operation) => Some(operation),
100 Instruction::Yield => None,
101 }
102 }
103}
104impl<T: fmt::Debug> fmt::Debug for Instruction<T> {
105 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
106 match self {
107 Instruction::Mutate(operation) => fmt::Debug::fmt(operation, f),
108 Instruction::Yield => f.pad("Yield"),
109 }
110 }
111}
112
113#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
115pub enum Operation<T> {
116 Push(T),
118
119 Pop,
121}
122impl<T> Operation<T> {
123 #[inline]
134 pub fn into_item(self) -> Option<T> {
135 match self {
136 Operation::Push(item) => Some(item),
137 Operation::Pop => None,
138 }
139 }
140
141 #[inline]
152 pub fn as_item(&self) -> Option<&T> {
153 match self {
154 Operation::Push(item) => Some(item),
155 Operation::Pop => None,
156 }
157 }
158}
159
160pub trait Contract {
162 fn contract(&mut self, count: usize);
173}
174
175fn stack_extend<T>(
176 stack: &mut (impl Extend<T> + Contract),
177 mut iter: impl Iterator<Item = Operation<T>>,
178) {
179 loop {
181 let mut pop_count = 0;
184 stack.extend(iter.by_ref().map_while(|op| match op {
185 Operation::Push(val) => Some(val),
186 Operation::Pop => {
187 pop_count = 1;
188 None
189 }
190 }));
191
192 if pop_count == 0 {
194 return;
195 }
196
197 let mut next = None;
200
201 pop_count += iter
203 .by_ref()
204 .map_while(|op| match op {
205 Operation::Pop => Some(()),
206 Operation::Push(val) => {
207 next = Some(val);
208 None
209 }
210 })
211 .count();
212 stack.contract(pop_count);
213
214 if let Some(val) = next {
216 stack.extend(Some(val));
217 } else {
218 return;
219 }
220 }
221}
222
223#[cold]
225#[track_caller]
226fn panic_imploded(count: usize, len: usize) -> ! {
227 if len == 1 {
228 panic!("cannot contract by {count} when collection has 1 element");
229 } else {
230 panic!("cannot contract by {count} when collection has {len} elements")
231 }
232}
233
234#[cfg(feature = "alloc")]
236impl<T> Contract for Vec<T> {
237 #[track_caller]
238 fn contract(&mut self, count: usize) {
239 if count > self.len() {
240 panic_imploded(count, self.len())
241 }
242 self.truncate(self.len() - count);
243 }
244}
245#[cfg(feature = "alloc")]
247impl<T> Contract for VecDeque<T> {
248 #[track_caller]
249 fn contract(&mut self, count: usize) {
250 if count > self.len() {
251 panic_imploded(count, self.len())
252 }
253 self.truncate(self.len() - count);
254 }
255}
256#[cfg(feature = "alloc")]
258impl<T> Contract for LinkedList<T> {
259 #[track_caller]
260 fn contract(&mut self, count: usize) {
261 if count > self.len() {
263 panic_imploded(count, self.len())
264 }
265 for _ in 0..count {
267 self.pop_back();
268 }
269 }
270}
271
272#[cfg(feature = "alloc")]
274impl Contract for String {
275 #[track_caller]
276 fn contract(&mut self, count: usize) {
277 let mut chars = self.chars();
278
279 if cfg!(debug_assertions) {
281 let mut excess = 0;
282 let mut amount = 0;
283 for _ in 0..count {
284 if chars.next_back().is_none() {
285 excess += 1;
286 } else {
287 amount += 1;
288 }
289 }
290 if excess > 0 {
291 panic_imploded(count, amount);
292 }
293 } else {
294 chars.nth_back(count);
295 }
296
297 let len = chars.as_str().len();
298 self.truncate(len);
299 }
300}
301
302#[cfg(feature = "alloc")]
303impl<T> Extend<Operation<T>> for Vec<T> {
304 #[inline]
305 fn extend<I: IntoIterator<Item = Operation<T>>>(&mut self, iter: I) {
306 stack_extend(self, iter.into_iter())
307 }
308}
309#[cfg(feature = "alloc")]
310impl<T> Extend<Operation<T>> for VecDeque<T> {
311 #[inline]
312 fn extend<I: IntoIterator<Item = Operation<T>>>(&mut self, iter: I) {
313 stack_extend(self, iter.into_iter())
314 }
315}
316#[cfg(feature = "alloc")]
317impl<T> Extend<Operation<T>> for LinkedList<T> {
318 #[inline]
319 fn extend<I: IntoIterator<Item = Operation<T>>>(&mut self, iter: I) {
320 stack_extend(self, iter.into_iter())
321 }
322}
323
324pub trait StackingIteratorExt<T>: Iterator<Item = Instruction<T>> {
326 #[inline]
346 fn collecting<C: Default + Clone + Extend<T> + Contract>(self) -> Collecting<Self, C>
347 where
348 Self: Sized,
349 {
350 Collecting {
351 iter: self,
352 collection: Default::default(),
353 }
354 }
355
356 #[inline]
389 fn operate<'c, C: Extend<T> + Contract>(&mut self, collection: &'c mut C) -> Option<&'c C> {
390 let mut yielding = false;
391 stack_extend(
392 collection,
393 self.map_while(|inst| match inst {
394 Instruction::Mutate(operation) => Some(operation),
395 Instruction::Yield => {
396 yielding = true;
397 None
398 }
399 }),
400 );
401 if yielding {
402 Some(collection)
403 } else {
404 None
405 }
406 }
407}
408impl<T, I: Iterator<Item = Instruction<T>>> StackingIteratorExt<T> for I {}
409
410#[derive(Clone, Debug)]
412pub struct Collecting<I, C> {
413 iter: I,
414 collection: C,
415}
416impl<T, I: Iterator<Item = Instruction<T>>, C: Clone + Extend<T> + Contract> Iterator
417 for Collecting<I, C>
418{
419 type Item = C;
420
421 #[inline]
422 fn next(&mut self) -> Option<C> {
423 self.iter.operate(&mut self.collection).cloned()
424 }
425
426 #[inline]
427 fn size_hint(&self) -> (usize, Option<usize>) {
428 let (_, hi) = self.iter.size_hint();
429
430 (0, hi)
432 }
433}
434
435#[cfg(test)]
436mod tests {
437 use core::iter::repeat;
438
439 use super::{Contract, Instruction, Operation, StackingIteratorExt};
440 use alloc::collections::{LinkedList, VecDeque};
441
442 macro_rules! seq {
443 (@ $stack:expr; - $($item:tt)*) => {
444 $stack.push(Instruction::Mutate(Operation::Pop));
445 seq!(@ $stack; $($item)*);
446 };
447 (@ $stack:expr; + $($item:tt)*) => {
448 $stack.push(Instruction::Yield);
449 seq!(@ $stack; $($item)*);
450 };
451 (@ $stack:expr; $val:ident $($item:tt)*) => {
452 $stack.push(Instruction::Mutate(Operation::Push(stringify!($val))));
453 seq!(@ $stack; $($item)*);
454 };
455 (@ $stack:expr;) => {
456 };
457 ($($item:tt)*) => {
458 {
459 #[allow(unused_mut)]
460 let mut stack: Vec<Instruction<&'static str>> = Vec::new();
461 seq!(@ stack; $($item)*);
462 stack.into_iter()
463 }
464 };
465 }
466
467 #[test]
468 fn contract_vec() {
469 let mut v = vec![1, 2, 3, 4, 5];
470 assert_eq!(v, [1, 2, 3, 4, 5]);
471 v.contract(0);
472 assert_eq!(v, [1, 2, 3, 4, 5]);
473 v.contract(2);
474 assert_eq!(v, [1, 2, 3]);
475 v.contract(3);
476 assert_eq!(v, []);
477 v.contract(0);
478 }
479
480 #[test]
481 fn contract_vec_deque() {
482 let mut v = VecDeque::from(vec![1, 2, 3, 4, 5]);
483 assert_eq!(v, [1, 2, 3, 4, 5]);
484 v.contract(0);
485 assert_eq!(v, [1, 2, 3, 4, 5]);
486 v.contract(2);
487 assert_eq!(v, [1, 2, 3]);
488 v.contract(3);
489 assert_eq!(v, []);
490 v.contract(0);
491 }
492
493 #[test]
494 fn contract_linked_list() {
495 let mut l = LinkedList::from([1, 2, 3, 4, 5]);
496 assert_eq!(l.iter().copied().collect::<Vec<_>>(), [1, 2, 3, 4, 5]);
497 l.contract(0);
498 assert_eq!(l.iter().copied().collect::<Vec<_>>(), [1, 2, 3, 4, 5]);
499 l.contract(2);
500 assert_eq!(l.iter().copied().collect::<Vec<_>>(), [1, 2, 3]);
501 l.contract(3);
502 assert_eq!(l.iter().copied().collect::<Vec<_>>(), []);
503 l.contract(0);
504 }
505
506 #[test]
507 fn contract_string() {
508 let mut s = "世界こんにちは".to_owned();
509 assert_eq!(s, "世界こんにちは");
510 s.contract(0);
511 assert_eq!(s, "世界こんにちは");
512 s.contract(5);
513 assert_eq!(s, "世界");
514 s.contract(1);
515 assert_eq!(s, "世");
516 s.contract(1);
517 assert_eq!(s, "");
518 s.contract(0);
519 }
520
521 #[test]
522 #[should_panic = "cannot contract by 1 when collection has 0 elements"]
523 fn implode_empty_vec() {
524 let mut v = <Vec<()>>::new();
525 v.contract(1);
526 }
527
528 #[test]
529 #[should_panic = "cannot contract by 2 when collection has 1 element"]
530 fn implode_vec() {
531 let mut v = vec![1];
532 v.contract(2);
533 }
534
535 #[test]
536 #[should_panic = "cannot contract by 1 when collection has 0 elements"]
537 fn implode_empty_vec_deque() {
538 let mut v = <VecDeque<()>>::new();
539 v.contract(1);
540 }
541
542 #[test]
543 #[should_panic = "cannot contract by 2 when collection has 1 element"]
544 fn implode_vec_deque() {
545 let mut v = VecDeque::from([1]);
546 v.contract(2);
547 }
548
549 #[test]
550 #[should_panic = "cannot contract by 1 when collection has 0 elements"]
551 fn implode_empty_linked_list() {
552 let mut l = <LinkedList<()>>::new();
553 l.contract(1);
554 }
555
556 #[test]
557 #[should_panic = "cannot contract by 2 when collection has 1 element"]
558 fn implode_linked_list() {
559 let mut l = LinkedList::from([1]);
560 l.contract(2);
561 }
562
563 #[test]
564 #[should_panic = "cannot contract by 1 when collection has 0 elements"]
565 fn implode_empty_string() {
566 let mut s = String::new();
567 s.contract(1);
568 }
569
570 #[test]
571 #[should_panic = "cannot contract by 2 when collection has 1 element"]
572 fn implode_string() {
573 let mut l = "あ".to_owned();
574 l.contract(2);
575 }
576
577 #[test]
578 fn extend_push() {
579 let mut v = vec![1, 2, 3];
580 v.extend([4, 5, 6].into_iter().map(Operation::Push));
581 assert_eq!(v, [1, 2, 3, 4, 5, 6]);
582 }
583
584 #[test]
585 fn extend_pop() {
586 let mut v = vec![1, 2, 3];
587 v.extend(repeat(Operation::Pop).take(2));
588 assert_eq!(v, [1]);
589 }
590
591 #[test]
592 fn empty() {
593 let seq = seq!();
594 assert_eq!(seq.collecting::<String>().next(), None);
595 }
596
597 #[test]
598 fn sneaky_empty() {
599 let seq = seq!(h e l l o);
600 let mut iter = seq.collecting::<String>();
601 assert_eq!(iter.next(), None);
602 }
603
604 #[test]
605 fn hello() {
606 let seq = seq!(h e l l o +);
607 let mut iter = seq.collecting::<String>();
608 assert_eq!(iter.next().as_deref(), Some("hello"));
609 assert_eq!(iter.next(), None);
610 }
611
612 #[test]
613 fn hello_hell() {
614 let seq = seq!(h e l l o + - +);
615 let collected: Vec<String> = seq.collecting().collect();
616 assert_eq!(collected, ["hello", "hell"]);
617 }
618
619 #[test]
620 fn hello_world() {
621 let seq = seq!(h e l l o + - + - - - - w o r l d +);
622 let collected: Vec<String> = seq.collecting().collect();
623 assert_eq!(collected, ["hello", "hell", "world"]);
624 }
625}