Skip to content

Commit c79d71b

Browse files
committed
Implement Sequence for arrays
1 parent 70fadf2 commit c79d71b

File tree

1 file changed

+120
-2
lines changed

1 file changed

+120
-2
lines changed

enum-iterator/src/lib.rs

Lines changed: 120 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@
6464
#![deny(warnings)]
6565
#![no_std]
6666

67-
use core::iter::FusedIterator;
67+
use core::{iter::FusedIterator, ops::ControlFlow};
6868

6969
pub use enum_iterator_derive::Sequence;
7070

@@ -527,6 +527,69 @@ impl<T: Sequence> Sequence for Option<T> {
527527
}
528528
}
529529

530+
impl<const N: usize, T: Sequence + Clone> Sequence for [T; N] {
531+
const CARDINALITY: usize = {
532+
let tc = T::CARDINALITY;
533+
let mut c = 1;
534+
let mut i = 0;
535+
loop {
536+
if i == N {
537+
break c;
538+
}
539+
c *= tc;
540+
i += 1;
541+
}
542+
};
543+
544+
fn next(&self) -> Option<Self> {
545+
advance_for_array(self, T::first)
546+
}
547+
548+
fn previous(&self) -> Option<Self> {
549+
advance_for_array(self, T::last)
550+
}
551+
552+
fn first() -> Option<Self> {
553+
if N == 0 {
554+
Some(core::array::from_fn(|_| unreachable!()))
555+
} else {
556+
let x = T::first()?;
557+
Some(core::array::from_fn(|_| x.clone()))
558+
}
559+
}
560+
561+
fn last() -> Option<Self> {
562+
if N == 0 {
563+
Some(core::array::from_fn(|_| unreachable!()))
564+
} else {
565+
let x = T::last()?;
566+
Some(core::array::from_fn(|_| x.clone()))
567+
}
568+
}
569+
}
570+
571+
fn advance_for_array<const N: usize, T, R>(a: &[T; N], reset: R) -> Option<[T; N]>
572+
where
573+
T: Sequence + Clone,
574+
R: Fn() -> Option<T>,
575+
{
576+
let mut a = a.clone();
577+
let keep = a.iter_mut().rev().try_fold((), |_, x| match x.next() {
578+
Some(new_x) => {
579+
*x = new_x;
580+
ControlFlow::Break(true)
581+
}
582+
None => match reset() {
583+
Some(new_x) => {
584+
*x = new_x;
585+
ControlFlow::Continue(())
586+
}
587+
None => ControlFlow::Break(false),
588+
},
589+
});
590+
Some(a).filter(|_| matches!(keep, ControlFlow::Break(true)))
591+
}
592+
530593
macro_rules! impl_seq_advance_for_tuple {
531594
(
532595
$this:ident,
@@ -778,7 +841,7 @@ mod tests {
778841
}
779842

780843
#[test]
781-
fn check_option_items() {
844+
fn all_bool_option_items_are_yielded() {
782845
assert!(all::<Option<bool>>().eq([None, Some(false), Some(true)]));
783846
}
784847

@@ -793,4 +856,59 @@ mod tests {
793856
(Some(true), true),
794857
]));
795858
}
859+
860+
#[test]
861+
fn cardinality_of_empty_array_is_one() {
862+
assert_eq!(cardinality::<[u8; 0]>(), 1);
863+
}
864+
865+
#[test]
866+
fn cardinality_equals_item_count_for_empty_array() {
867+
cardinality_equals_item_count::<[u8; 0]>();
868+
}
869+
870+
#[test]
871+
fn cardinality_equals_item_count_for_array() {
872+
cardinality_equals_item_count::<[u8; 3]>();
873+
}
874+
875+
#[test]
876+
fn array_items_vary_from_right_to_left() {
877+
assert!(all::<[Option<bool>; 2]>().eq([
878+
[None, None],
879+
[None, Some(false)],
880+
[None, Some(true)],
881+
[Some(false), None],
882+
[Some(false), Some(false)],
883+
[Some(false), Some(true)],
884+
[Some(true), None],
885+
[Some(true), Some(false)],
886+
[Some(true), Some(true)],
887+
]));
888+
}
889+
890+
#[test]
891+
fn all_empty_array_items_are_yielded() {
892+
assert!(all::<[bool; 0]>().eq([[]]));
893+
}
894+
895+
#[test]
896+
fn cardinality_of_empty_infallible_array_is_one() {
897+
assert_eq!(cardinality::<[Infallible; 0]>(), 1);
898+
}
899+
900+
#[test]
901+
fn cardinality_of_non_empty_infallible_array_is_zero() {
902+
assert_eq!(cardinality::<[Infallible; 1]>(), 0);
903+
}
904+
905+
#[test]
906+
fn all_empty_infallible_array_items_are_yielded() {
907+
assert!(all::<[Infallible; 0]>().eq([[]]));
908+
}
909+
910+
#[test]
911+
fn all_non_empty_infallible_array_items_are_yielded() {
912+
assert!(all::<[Infallible; 1]>().next().is_none());
913+
}
796914
}

0 commit comments

Comments
 (0)