Import enum-iterator 2.1.0 upstream upstream/2.1.0
authorDongHun Kwak <dh0128.kwak@samsung.com>
Thu, 22 May 2025 06:00:21 +0000 (15:00 +0900)
committerDongHun Kwak <dh0128.kwak@samsung.com>
Thu, 22 May 2025 06:00:21 +0000 (15:00 +0900)
.cargo_vcs_info.json [new file with mode: 0644]
Cargo.toml [new file with mode: 0644]
Cargo.toml.orig [new file with mode: 0644]
LICENSE [new file with mode: 0644]
README.md [new file with mode: 0644]
src/lib.rs [new file with mode: 0644]
tests/derive.rs [new file with mode: 0644]

diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json
new file mode 100644 (file)
index 0000000..12e6342
--- /dev/null
@@ -0,0 +1,6 @@
+{
+  "git": {
+    "sha1": "2b1aaefe6de0ccea827b1376ebad12f3476662a9"
+  },
+  "path_in_vcs": "enum-iterator"
+}
\ No newline at end of file
diff --git a/Cargo.toml b/Cargo.toml
new file mode 100644 (file)
index 0000000..669a023
--- /dev/null
@@ -0,0 +1,32 @@
+# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
+#
+# When uploading crates to the registry Cargo will automatically
+# "normalize" Cargo.toml files for maximal compatibility
+# with all versions of Cargo and also rewrite `path` dependencies
+# to registry (e.g., crates.io) dependencies.
+#
+# If you are reading this file be aware that the original Cargo.toml
+# will likely look very different (and much more reasonable).
+# See Cargo.toml.orig for the original contents.
+
+[package]
+edition = "2021"
+name = "enum-iterator"
+version = "2.1.0"
+authors = ["Stephane Raux <stephaneyfx@gmail.com>"]
+description = "Tools to iterate over all values of a type (e.g. all variants of an enumeration)"
+homepage = "https://github.com/stephaneyfx/enum-iterator"
+documentation = "https://docs.rs/enum-iterator"
+readme = "README.md"
+keywords = [
+    "enum",
+    "variants",
+    "iterator",
+    "enumerate",
+    "cardinality",
+]
+license = "0BSD"
+repository = "https://github.com/stephaneyfx/enum-iterator.git"
+
+[dependencies.enum-iterator-derive]
+version = "1.4.0"
diff --git a/Cargo.toml.orig b/Cargo.toml.orig
new file mode 100644 (file)
index 0000000..24257c1
--- /dev/null
@@ -0,0 +1,14 @@
+[package]
+name = "enum-iterator"
+version = "2.1.0"
+authors = ["Stephane Raux <stephaneyfx@gmail.com>"]
+edition = "2021"
+description = "Tools to iterate over all values of a type (e.g. all variants of an enumeration)"
+license = "0BSD"
+homepage = "https://github.com/stephaneyfx/enum-iterator"
+repository = "https://github.com/stephaneyfx/enum-iterator.git"
+documentation = "https://docs.rs/enum-iterator"
+keywords = ["enum", "variants", "iterator", "enumerate", "cardinality"]
+
+[dependencies]
+enum-iterator-derive = { path = "../enum-iterator-derive", version = "1.4.0" }
diff --git a/LICENSE b/LICENSE
new file mode 100644 (file)
index 0000000..639dbea
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,14 @@
+BSD Zero Clause License
+
+Copyright (c) 2018 Stephane Raux
+
+Permission to use, copy, modify, and/or distribute this software for any
+purpose with or without fee is hereby granted.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
+REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
+INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+PERFORMANCE OF THIS SOFTWARE.
diff --git a/README.md b/README.md
new file mode 100644 (file)
index 0000000..54b0c51
--- /dev/null
+++ b/README.md
@@ -0,0 +1,63 @@
+<!-- cargo-sync-readme start -->
+
+# Overview
+- [📦 crates.io](https://crates.io/crates/enum-iterator)
+- [📖 Documentation](https://docs.rs/enum-iterator)
+- [âš– 0BSD license](https://spdx.org/licenses/0BSD.html)
+
+Tools to iterate over the values of a type.
+
+# Examples
+```rust
+use enum_iterator::{all, cardinality, first, last, next, previous, reverse_all, Sequence};
+
+#[derive(Debug, PartialEq, Sequence)]
+enum Day { Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday }
+
+assert_eq!(cardinality::<Day>(), 7);
+assert_eq!(all::<Day>().collect::<Vec<_>>(), [
+    Day::Monday,
+    Day::Tuesday,
+    Day::Wednesday,
+    Day::Thursday,
+    Day::Friday,
+    Day::Saturday,
+    Day::Sunday,
+]);
+assert_eq!(first::<Day>(), Some(Day::Monday));
+assert_eq!(last::<Day>(), Some(Day::Sunday));
+assert_eq!(next(&Day::Tuesday), Some(Day::Wednesday));
+assert_eq!(previous(&Day::Wednesday), Some(Day::Tuesday));
+assert_eq!(reverse_all::<Day>().collect::<Vec<_>>(), [
+    Day::Sunday,
+    Day::Saturday,
+    Day::Friday,
+    Day::Thursday,
+    Day::Wednesday,
+    Day::Tuesday,
+    Day::Monday,
+]);
+```
+
+```rust
+use enum_iterator::{cardinality, first, last, Sequence};
+
+#[derive(Debug, PartialEq, Sequence)]
+struct Foo {
+    a: bool,
+    b: u8,
+}
+
+assert_eq!(cardinality::<Foo>(), 512);
+assert_eq!(first::<Foo>(), Some(Foo { a: false, b: 0 }));
+assert_eq!(last::<Foo>(), Some(Foo { a: true, b: 255 }));
+```
+
+# Rust version
+This crate tracks stable Rust. Minor releases may require a newer Rust version. Patch releases
+must not require a newer Rust version.
+
+# Contribute
+All contributions shall be licensed under the [0BSD license](https://spdx.org/licenses/0BSD.html).
+
+<!-- cargo-sync-readme end -->
diff --git a/src/lib.rs b/src/lib.rs
new file mode 100644 (file)
index 0000000..16d4726
--- /dev/null
@@ -0,0 +1,1069 @@
+// Copyright (c) 2018-2022 Stephane Raux. Distributed under the 0BSD license.
+
+//! # Overview
+//! - [📦 crates.io](https://crates.io/crates/enum-iterator)
+//! - [📖 Documentation](https://docs.rs/enum-iterator)
+//! - [âš– 0BSD license](https://spdx.org/licenses/0BSD.html)
+//!
+//! Tools to iterate over the values of a type.
+//!
+//! # Examples
+//! ```
+//! use enum_iterator::{all, cardinality, first, last, next, previous, reverse_all, Sequence};
+//!
+//! #[derive(Debug, PartialEq, Sequence)]
+//! enum Day { Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday }
+//!
+//! assert_eq!(cardinality::<Day>(), 7);
+//! assert_eq!(all::<Day>().collect::<Vec<_>>(), [
+//!     Day::Monday,
+//!     Day::Tuesday,
+//!     Day::Wednesday,
+//!     Day::Thursday,
+//!     Day::Friday,
+//!     Day::Saturday,
+//!     Day::Sunday,
+//! ]);
+//! assert_eq!(first::<Day>(), Some(Day::Monday));
+//! assert_eq!(last::<Day>(), Some(Day::Sunday));
+//! assert_eq!(next(&Day::Tuesday), Some(Day::Wednesday));
+//! assert_eq!(previous(&Day::Wednesday), Some(Day::Tuesday));
+//! assert_eq!(reverse_all::<Day>().collect::<Vec<_>>(), [
+//!     Day::Sunday,
+//!     Day::Saturday,
+//!     Day::Friday,
+//!     Day::Thursday,
+//!     Day::Wednesday,
+//!     Day::Tuesday,
+//!     Day::Monday,
+//! ]);
+//! ```
+//!
+//! ```
+//! use enum_iterator::{cardinality, first, last, Sequence};
+//!
+//! #[derive(Debug, PartialEq, Sequence)]
+//! struct Foo {
+//!     a: bool,
+//!     b: u8,
+//! }
+//!
+//! assert_eq!(cardinality::<Foo>(), 512);
+//! assert_eq!(first::<Foo>(), Some(Foo { a: false, b: 0 }));
+//! assert_eq!(last::<Foo>(), Some(Foo { a: true, b: 255 }));
+//! ```
+//!
+//! # Rust version
+//! This crate tracks stable Rust. Minor releases may require a newer Rust version. Patch releases
+//! must not require a newer Rust version.
+//!
+//! # Contribute
+//! All contributions shall be licensed under the [0BSD license](https://spdx.org/licenses/0BSD.html).
+
+#![deny(missing_docs)]
+#![deny(warnings)]
+#![no_std]
+
+use core::{cmp::Ordering, iter::FusedIterator, ops::ControlFlow, task::Poll};
+
+pub use enum_iterator_derive::Sequence;
+
+/// Returns the cardinality (number of values) of `T`
+///
+/// # Example
+/// ```
+/// use enum_iterator::{cardinality, Sequence};
+///
+/// #[derive(Debug, PartialEq, Sequence)]
+/// enum Color { Red, Green, Blue }
+///
+/// assert_eq!(cardinality::<Color>(), 3);
+/// ```
+pub const fn cardinality<T: Sequence>() -> usize {
+    T::CARDINALITY
+}
+
+/// Returns an iterator over all values of type `T`.
+///
+/// Values are yielded in the order defined by [`Sequence::next`], starting with
+/// [`Sequence::first`].
+///
+/// # Example
+/// ```
+/// use enum_iterator::{all, Sequence};
+///
+/// #[derive(Debug, PartialEq, Sequence)]
+/// enum Color { Red, Green, Blue }
+///
+/// assert_eq!(
+///     all::<Color>().collect::<Vec<_>>(),
+///     [Color::Red, Color::Green, Color::Blue],
+/// );
+/// ```
+pub fn all<T: Sequence>() -> All<T> {
+    All(T::first())
+}
+
+/// Returns an iterator over all values of type `T` in the reverse order of [`all`].
+///
+/// # Example
+/// ```
+/// use enum_iterator::{reverse_all, Sequence};
+///
+/// #[derive(Debug, PartialEq, Sequence)]
+/// enum Color { Red, Green, Blue }
+///
+/// assert_eq!(
+///     reverse_all::<Color>().collect::<Vec<_>>(),
+///     [Color::Blue, Color::Green, Color::Red],
+/// );
+/// ```
+pub fn reverse_all<T: Sequence>() -> ReverseAll<T> {
+    ReverseAll(T::last())
+}
+
+/// Returns the next value of type `T` or `None` if this was the end.
+///
+/// Same as [`Sequence::next`].
+///
+/// # Example
+/// ```
+/// use enum_iterator::{next, Sequence};
+///
+/// #[derive(Debug, PartialEq, Sequence)]
+/// enum Day { Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday }
+///
+/// assert_eq!(next(&Day::Friday), Some(Day::Saturday));
+/// ```
+pub fn next<T: Sequence>(x: &T) -> Option<T> {
+    x.next()
+}
+
+/// Returns the next value of type `T` or [`first()`](first) if this was the end.
+///
+/// # Example
+/// ```
+/// use enum_iterator::{next_cycle, Sequence};
+///
+/// #[derive(Debug, PartialEq, Sequence)]
+/// enum Day { Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday }
+///
+/// assert_eq!(next_cycle(&Day::Sunday), Day::Monday);
+/// ```
+pub fn next_cycle<T: Sequence>(x: &T) -> T {
+    next(x)
+        .or_else(first)
+        .expect("Sequence::first returned None for inhabited type")
+}
+
+/// Returns the previous value of type `T` or `None` if this was the beginning.
+///
+/// Same as [`Sequence::previous`].
+///
+/// # Example
+/// ```
+/// use enum_iterator::{previous, Sequence};
+///
+/// #[derive(Debug, PartialEq, Sequence)]
+/// enum Day { Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday }
+///
+/// assert_eq!(previous(&Day::Saturday), Some(Day::Friday));
+/// ```
+pub fn previous<T: Sequence>(x: &T) -> Option<T> {
+    x.previous()
+}
+
+/// Returns the previous value of type `T` or [`last()`](last) if this was the beginning.
+///
+/// # Example
+/// ```
+/// use enum_iterator::{previous_cycle, Sequence};
+///
+/// #[derive(Debug, PartialEq, Sequence)]
+/// enum Day { Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday }
+///
+/// assert_eq!(previous_cycle(&Day::Monday), Day::Sunday);
+/// ```
+pub fn previous_cycle<T: Sequence>(x: &T) -> T {
+    previous(x)
+        .or_else(last)
+        .expect("Sequence::last returned None for inhabited type")
+}
+
+/// Returns the first value of type `T`.
+///
+/// Same as [`Sequence::first`].
+///
+/// # Example
+/// ```
+/// use enum_iterator::{first, Sequence};
+///
+/// #[derive(Debug, PartialEq, Sequence)]
+/// enum Day { Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday }
+///
+/// assert_eq!(first::<Day>(), Some(Day::Monday));
+/// ```
+pub fn first<T: Sequence>() -> Option<T> {
+    T::first()
+}
+
+/// Returns the last value of type `T`.
+///
+/// Same as [`Sequence::last`].
+///
+/// # Example
+/// ```
+/// use enum_iterator::{last, Sequence};
+///
+/// #[derive(Debug, PartialEq, Sequence)]
+/// enum Day { Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday }
+///
+/// assert_eq!(last::<Day>(), Some(Day::Sunday));
+/// ```
+pub fn last<T: Sequence>() -> Option<T> {
+    T::last()
+}
+
+/// Iterator over the values of type `T`.
+///
+/// Returned by [`all`].
+#[derive(Clone, Debug)]
+pub struct All<T>(Option<T>);
+
+impl<T: Sequence> Iterator for All<T> {
+    type Item = T;
+
+    fn next(&mut self) -> Option<T> {
+        let item = self.0.take()?;
+        self.0 = item.next();
+        Some(item)
+    }
+}
+
+impl<T: Sequence> FusedIterator for All<T> {}
+
+/// Iterator over the values of type `T` in reverse order.
+///
+/// Returned by [`reverse_all`].
+#[derive(Clone, Debug)]
+pub struct ReverseAll<T>(Option<T>);
+
+impl<T: Sequence> Iterator for ReverseAll<T> {
+    type Item = T;
+
+    fn next(&mut self) -> Option<T> {
+        let item = self.0.take()?;
+        self.0 = item.previous();
+        Some(item)
+    }
+}
+
+impl<T: Sequence> FusedIterator for ReverseAll<T> {}
+
+/// Trait to iterate over the values of a type.
+///
+/// The [crate root](crate) defines useful functions to work with types implementing `Sequence`.
+///
+/// # Derivation
+///
+/// `Sequence` can be derived for `enum` and `struct` types. Specifically, it can be derived
+/// for:
+/// - Enumerations whose variants meet one of the following criteria:
+///   - The variant does not have fields.
+///   - The variant has fields meeting all these conditions:
+///     - Every field has a type that implements `Sequence`.
+///     - Every field but the last one has a type that implements `Clone`.
+/// - Enumerations without variants.
+/// - Structures whose fields meet all these conditions:
+///     - Every field has a type that implements `Sequence`.
+///     - Every field but the last one has a type that implements `Clone`.
+/// - Unit structures (i.e. without fields).
+///
+/// The cardinality (number of values) of the type must not exceed `usize::MAX`.
+///
+/// # Laws
+///
+/// `T: Sequence` implies the following assertions:
+/// - `T::first().and_then(|x| x.previous()).is_none()`
+/// - `T::last().and_then(|x| x.next()).is_none()`
+/// - `T::first().is_none()` â‡” `T::last().is_none()`
+/// - `std::iter::successors(T::first(), T::next)` must eventually yield `T::last()`.
+/// - If `T` is inhabited, `T::first().is_some()`.
+///
+/// If a manual implementation of `Sequence` violates any of these laws, the functions at the crate root may misbehave, including panicking.
+///
+/// # Examples
+/// ## C-like enumeration
+///
+/// ```
+/// use enum_iterator::{all, cardinality, Sequence};
+///
+/// #[derive(Clone, Copy, Debug, PartialEq, Sequence)]
+/// enum Direction { North, South, West, East }
+///
+/// assert_eq!(cardinality::<Direction>(), 4);
+/// assert_eq!(all::<Direction>().collect::<Vec<_>>(), [
+///     Direction::North,
+///     Direction::South,
+///     Direction::West,
+///     Direction::East,
+/// ]);
+/// ```
+///
+/// ## Enumeration with data
+///
+/// ```
+/// use enum_iterator::{all, cardinality, Sequence};
+///
+/// #[derive(Clone, Copy, Debug, PartialEq, Sequence)]
+/// enum Direction { North, South, West, East }
+///
+/// #[derive(Clone, Copy, Debug, PartialEq, Sequence)]
+/// enum Greeting {
+///     Hi,
+///     Bye,
+/// }
+///
+/// #[derive(Clone, Copy, Debug, PartialEq, Sequence)]
+/// enum Action {
+///     Move(Direction),
+///     Jump,
+///     Talk { greeting: Greeting, loud: bool },
+/// }
+///
+/// assert_eq!(cardinality::<Action>(), 4 + 1 + 2 * 2);
+/// assert_eq!(all::<Action>().collect::<Vec<_>>(), [
+///     Action::Move(Direction::North),
+///     Action::Move(Direction::South),
+///     Action::Move(Direction::West),
+///     Action::Move(Direction::East),
+///     Action::Jump,
+///     Action::Talk { greeting: Greeting::Hi, loud: false },
+///     Action::Talk { greeting: Greeting::Hi, loud: true },
+///     Action::Talk { greeting: Greeting::Bye, loud: false },
+///     Action::Talk { greeting: Greeting::Bye, loud: true },
+/// ]);
+/// ```
+///
+/// ## Structure
+///
+/// ```
+/// use enum_iterator::{all, cardinality, Sequence};
+///
+/// #[derive(Clone, Copy, Debug, PartialEq, Sequence)]
+/// enum Side {
+///     Left,
+///     Right,
+/// }
+///
+/// #[derive(Clone, Copy, Debug, PartialEq, Sequence)]
+/// enum LimbKind {
+///     Arm,
+///     Leg,
+/// }
+///
+/// #[derive(Debug, PartialEq, Sequence)]
+/// struct Limb {
+///     kind: LimbKind,
+///     side: Side,
+/// }
+///
+/// assert_eq!(cardinality::<Limb>(), 4);
+/// assert_eq!(all::<Limb>().collect::<Vec<_>>(), [
+///     Limb { kind: LimbKind::Arm, side: Side::Left },
+///     Limb { kind: LimbKind::Arm, side: Side::Right },
+///     Limb { kind: LimbKind::Leg, side: Side::Left },
+///     Limb { kind: LimbKind::Leg, side: Side::Right },
+/// ]);
+/// ```
+pub trait Sequence: Sized {
+    /// Number of values of type `Self`.
+    ///
+    /// # Example
+    /// ```
+    /// use enum_iterator::Sequence;
+    ///
+    /// #[derive(Sequence)]
+    /// enum Day { Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday }
+    ///
+    /// assert_eq!(Day::CARDINALITY, 7);
+    /// ```
+    const CARDINALITY: usize;
+
+    /// Returns value following `*self` or `None` if this was the end.
+    ///
+    /// Values are yielded in the following order. Comparisons between values are based on their
+    /// relative order as yielded by `next`; an element yielded after another is considered greater.
+    ///
+    /// - For primitive types, in increasing order (same as `Ord`).
+    /// - For arrays and tuples, in lexicographic order of the sequence of their elements.
+    /// - When derived for an enumeration, in variant definition order.
+    /// - When derived for a structure, in lexicographic order of the sequence of its fields taken
+    ///   in definition order.
+    ///
+    /// The order described above is the same as `Ord` if any custom `Sequence` implementation
+    /// follows `Ord` and any enumeration has its variants defined in increasing order of
+    /// discriminant.
+    ///
+    /// # Example
+    /// ```
+    /// use enum_iterator::Sequence;
+    ///
+    /// #[derive(Debug, PartialEq, Sequence)]
+    /// enum Day { Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday }
+    ///
+    /// assert_eq!(Day::Tuesday.next(), Some(Day::Wednesday));
+    /// ```
+    fn next(&self) -> Option<Self>;
+
+    /// Returns value preceding `*self` or `None` if this was the beginning.
+    ///
+    /// # Example
+    /// ```
+    /// use enum_iterator::Sequence;
+    ///
+    /// #[derive(Debug, PartialEq, Sequence)]
+    /// enum Day { Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday }
+    ///
+    /// assert_eq!(Day::Wednesday.previous(), Some(Day::Tuesday));
+    /// ```
+    fn previous(&self) -> Option<Self>;
+
+    /// Returns the first value of type `Self`.
+    ///
+    /// # Example
+    /// ```
+    /// use enum_iterator::Sequence;
+    ///
+    /// #[derive(Debug, PartialEq, Sequence)]
+    /// enum Day { Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday }
+    ///
+    /// assert_eq!(Day::first(), Some(Day::Monday));
+    /// ```
+    fn first() -> Option<Self>;
+
+    /// Returns the last value of type `Self`.
+    ///
+    /// # Example
+    /// ```
+    /// use enum_iterator::Sequence;
+    ///
+    /// #[derive(Debug, PartialEq, Sequence)]
+    /// enum Day { Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday }
+    ///
+    /// assert_eq!(Day::last(), Some(Day::Sunday));
+    /// ```
+    fn last() -> Option<Self>;
+}
+
+impl Sequence for bool {
+    const CARDINALITY: usize = 2;
+
+    fn next(&self) -> Option<Self> {
+        (!*self).then_some(true)
+    }
+
+    fn previous(&self) -> Option<Self> {
+        (*self).then_some(false)
+    }
+
+    fn first() -> Option<Self> {
+        Some(false)
+    }
+
+    fn last() -> Option<Self> {
+        Some(true)
+    }
+}
+
+macro_rules! impl_sequence_for_int {
+    ($ty:ty) => {
+        impl Sequence for $ty {
+            const CARDINALITY: usize = 1 << <$ty>::BITS;
+
+            fn next(&self) -> Option<Self> {
+                self.checked_add(1)
+            }
+
+            fn previous(&self) -> Option<Self> {
+                self.checked_sub(1)
+            }
+
+            fn first() -> Option<Self> {
+                Some(Self::MIN)
+            }
+
+            fn last() -> Option<Self> {
+                Some(Self::MAX)
+            }
+        }
+    };
+}
+
+impl_sequence_for_int!(i8);
+impl_sequence_for_int!(u8);
+impl_sequence_for_int!(i16);
+impl_sequence_for_int!(u16);
+
+impl Sequence for () {
+    const CARDINALITY: usize = 1;
+
+    fn next(&self) -> Option<Self> {
+        None
+    }
+
+    fn previous(&self) -> Option<Self> {
+        None
+    }
+
+    fn first() -> Option<Self> {
+        Some(())
+    }
+
+    fn last() -> Option<Self> {
+        Some(())
+    }
+}
+
+impl Sequence for core::convert::Infallible {
+    const CARDINALITY: usize = 0;
+
+    fn next(&self) -> Option<Self> {
+        None
+    }
+
+    fn previous(&self) -> Option<Self> {
+        None
+    }
+
+    fn first() -> Option<Self> {
+        None
+    }
+
+    fn last() -> Option<Self> {
+        None
+    }
+}
+
+impl Sequence for Ordering {
+    const CARDINALITY: usize = 3;
+
+    fn next(&self) -> Option<Self> {
+        int_to_ordering(*self as i8 + 1)
+    }
+
+    fn previous(&self) -> Option<Self> {
+        int_to_ordering(*self as i8 - 1)
+    }
+
+    fn first() -> Option<Self> {
+        Some(Ordering::Less)
+    }
+
+    fn last() -> Option<Self> {
+        Some(Ordering::Greater)
+    }
+}
+
+fn int_to_ordering(i: i8) -> Option<Ordering> {
+    match i {
+        -1 => Some(Ordering::Less),
+        0 => Some(Ordering::Equal),
+        1 => Some(Ordering::Greater),
+        _ => None,
+    }
+}
+
+impl<T: Sequence> Sequence for Option<T> {
+    const CARDINALITY: usize = T::CARDINALITY + 1;
+
+    fn next(&self) -> Option<Self> {
+        match self {
+            None => T::first().map(Some),
+            Some(x) => x.next().map(Some),
+        }
+    }
+
+    fn previous(&self) -> Option<Self> {
+        self.as_ref().map(T::previous)
+    }
+
+    fn first() -> Option<Self> {
+        Some(None)
+    }
+
+    fn last() -> Option<Self> {
+        Some(T::last())
+    }
+}
+
+impl<T: Sequence> Sequence for Poll<T> {
+    const CARDINALITY: usize = T::CARDINALITY + 1;
+
+    fn next(&self) -> Option<Self> {
+        match self {
+            Poll::Ready(x) => x.next().map(Poll::Ready).or(Some(Poll::Pending)),
+            Poll::Pending => None,
+        }
+    }
+
+    fn previous(&self) -> Option<Self> {
+        match self {
+            Poll::Ready(x) => x.previous().map(Poll::Ready),
+            Poll::Pending => T::last().map(Poll::Ready),
+        }
+    }
+
+    fn first() -> Option<Self> {
+        T::first().map(Poll::Ready).or(Some(Poll::Pending))
+    }
+
+    fn last() -> Option<Self> {
+        Some(Poll::Pending)
+    }
+}
+
+impl<const N: usize, T: Sequence + Clone> Sequence for [T; N] {
+    const CARDINALITY: usize = {
+        let tc = T::CARDINALITY;
+        let mut c = 1;
+        let mut i = 0;
+        loop {
+            if i == N {
+                break c;
+            }
+            c *= tc;
+            i += 1;
+        }
+    };
+
+    fn next(&self) -> Option<Self> {
+        advance_for_array(self, T::first)
+    }
+
+    fn previous(&self) -> Option<Self> {
+        advance_for_array(self, T::last)
+    }
+
+    fn first() -> Option<Self> {
+        if N == 0 {
+            Some(core::array::from_fn(|_| unreachable!()))
+        } else {
+            let x = T::first()?;
+            Some(core::array::from_fn(|_| x.clone()))
+        }
+    }
+
+    fn last() -> Option<Self> {
+        if N == 0 {
+            Some(core::array::from_fn(|_| unreachable!()))
+        } else {
+            let x = T::last()?;
+            Some(core::array::from_fn(|_| x.clone()))
+        }
+    }
+}
+
+fn advance_for_array<const N: usize, T, R>(a: &[T; N], reset: R) -> Option<[T; N]>
+where
+    T: Sequence + Clone,
+    R: Fn() -> Option<T>,
+{
+    let mut a = a.clone();
+    let keep = a.iter_mut().rev().try_fold((), |_, x| match x.next() {
+        Some(new_x) => {
+            *x = new_x;
+            ControlFlow::Break(true)
+        }
+        None => match reset() {
+            Some(new_x) => {
+                *x = new_x;
+                ControlFlow::Continue(())
+            }
+            None => ControlFlow::Break(false),
+        },
+    });
+    Some(a).filter(|_| matches!(keep, ControlFlow::Break(true)))
+}
+
+macro_rules! impl_seq_advance_for_tuple {
+    (
+        $this:ident,
+        $advance:ident,
+        $reset:ident,
+        $carry:ident
+        @ $($values:expr,)*
+        @
+        @ $($placeholders:pat,)*
+    ) => {
+        Some(($($values,)*)).filter(|_| !$carry)
+    };
+    (
+        $this:ident,
+        $advance:ident,
+        $reset:ident,
+        $carry:ident
+        @ $($values:expr,)*
+        @ $ty:ident, $($types:ident,)*
+        @ $($placeholders:pat,)*
+    ) => {{
+        let (.., item, $($placeholders,)*) = $this;
+        let (x, new_carry) = if $carry {
+            match Sequence::$advance(item) {
+                Some(x) => (x, false),
+                None => (Sequence::$reset()?, true),
+            }
+        } else {
+            (item.clone(), false)
+        };
+        impl_seq_advance_for_tuple!(
+            $this,
+            $advance,
+            $reset,
+            new_carry
+            @ x, $($values,)*
+            @ $($types,)*
+            @ _, $($placeholders,)*
+        )
+    }};
+    ($this:ident, $advance:ident, $reset:ident @ $($types:ident,)*) => {{
+        let (.., item) = $this;
+        let (x, carry) = match Sequence::$advance(item) {
+            Some(x) => (x, false),
+            None => (Sequence::$reset()?, true),
+        };
+        impl_seq_advance_for_tuple!($this, $advance, $reset, carry @ x, @ $($types,)* @ _,)
+    }};
+}
+
+macro_rules! impl_sequence_for_tuple {
+    ($($types:ident,)* @ $last:ident) => {
+        impl<$($types,)* $last> Sequence for ($($types,)* $last,)
+        where
+            $($types: Sequence + Clone,)*
+            $last: Sequence,
+        {
+            const CARDINALITY: usize =
+                $(<$types as Sequence>::CARDINALITY *)* <$last as Sequence>::CARDINALITY;
+
+            fn next(&self) -> Option<Self> {
+                impl_seq_advance_for_tuple!(self, next, first @ $($types,)*)
+            }
+
+            fn previous(&self) -> Option<Self> {
+                impl_seq_advance_for_tuple!(self, previous, last @ $($types,)*)
+            }
+
+            fn first() -> Option<Self> {
+                Some((
+                    $(<$types as Sequence>::first()?,)*
+                    <$last as Sequence>::first()?,
+                ))
+            }
+
+            fn last() -> Option<Self> {
+                Some((
+                    $(<$types as Sequence>::last()?,)*
+                    <$last as Sequence>::last()?,
+                ))
+            }
+        }
+    };
+}
+
+macro_rules! impl_sequence_for_tuples {
+    ($($types:ident,)*) => {
+        impl_sequence_for_tuples!(@ $($types,)*);
+    };
+    ($($types:ident,)* @ $head:ident, $($tail:ident,)*) => {
+        impl_sequence_for_tuple!($($types,)* @ $head);
+        impl_sequence_for_tuples!($($types,)* $head, @ $($tail,)*);
+    };
+    ($($types:ident,)* @) => {};
+}
+
+impl_sequence_for_tuples!(
+    T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20,
+    T21, T22, T23, T24, T25, T26, T27, T28, T29, T30, T31,
+);
+
+#[cfg(test)]
+mod tests {
+    use crate::{all, cardinality, reverse_all, Sequence};
+    use core::{cmp::Ordering, convert::Infallible, task::Poll};
+
+    fn cardinality_equals_item_count<T: Sequence>() {
+        assert_eq!(cardinality::<T>(), all::<T>().count());
+    }
+
+    #[test]
+    fn cardinality_equals_item_count_for_bool() {
+        cardinality_equals_item_count::<bool>();
+    }
+
+    #[test]
+    fn all_bool_values_are_yielded() {
+        assert!(all::<bool>().eq([false, true]));
+    }
+
+    #[test]
+    fn all_bool_values_are_yielded_in_reverse() {
+        assert!(reverse_all::<bool>().eq([true, false]));
+    }
+
+    #[test]
+    fn cardinality_equals_item_count_for_i8() {
+        cardinality_equals_item_count::<i8>();
+    }
+
+    #[test]
+    fn all_i8_values_are_yielded() {
+        assert!(all::<i8>().eq(i8::MIN..=i8::MAX));
+    }
+
+    #[test]
+    fn all_i8_values_are_yielded_in_reverse() {
+        assert!(reverse_all::<i8>().eq((i8::MIN..=i8::MAX).rev()));
+    }
+
+    #[test]
+    fn cardinality_equals_item_count_for_u8() {
+        cardinality_equals_item_count::<u8>();
+    }
+
+    #[test]
+    fn all_u8_values_are_yielded() {
+        assert!(all::<u8>().eq(u8::MIN..=u8::MAX));
+    }
+
+    #[test]
+    fn all_u8_values_are_yielded_in_reverse() {
+        assert!(reverse_all::<u8>().eq((u8::MIN..=u8::MAX).rev()));
+    }
+
+    #[test]
+    fn cardinality_equals_item_count_for_i16() {
+        cardinality_equals_item_count::<i16>();
+    }
+
+    #[test]
+    fn all_i16_values_are_yielded() {
+        assert!(all::<i16>().eq(i16::MIN..=i16::MAX));
+    }
+
+    #[test]
+    fn all_i16_values_are_yielded_in_reverse() {
+        assert!(reverse_all::<i16>().eq((i16::MIN..=i16::MAX).rev()));
+    }
+
+    #[test]
+    fn cardinality_equals_item_count_for_u16() {
+        cardinality_equals_item_count::<u16>();
+    }
+
+    #[test]
+    fn all_u16_values_are_yielded() {
+        assert!(all::<u16>().eq(u16::MIN..=u16::MAX));
+    }
+
+    #[test]
+    fn all_u16_values_are_yielded_in_reverse() {
+        assert!(reverse_all::<u16>().eq((u16::MIN..=u16::MAX).rev()));
+    }
+
+    #[test]
+    fn cardinality_equals_item_count_for_unit() {
+        cardinality_equals_item_count::<()>();
+    }
+
+    #[test]
+    fn all_unit_values_are_yielded() {
+        assert!(all::<()>().eq([()]));
+    }
+
+    #[test]
+    fn all_unit_values_are_yielded_in_reverse() {
+        assert!(reverse_all::<()>().eq([()]));
+    }
+
+    #[test]
+    fn cardinality_equals_item_count_for_infallible() {
+        cardinality_equals_item_count::<Infallible>();
+    }
+
+    #[test]
+    fn all_infallible_values_are_yielded() {
+        assert!(all::<Infallible>().next().is_none());
+    }
+
+    #[test]
+    fn all_infallible_values_are_yielded_in_reverse() {
+        assert!(reverse_all::<Infallible>().next().is_none());
+    }
+
+    #[test]
+    fn cardinality_equals_item_count_for_tuple_with_infallible() {
+        cardinality_equals_item_count::<(bool, Infallible)>();
+    }
+
+    #[test]
+    fn all_tuple_with_infallible_values_are_yielded() {
+        assert!(all::<(bool, Infallible)>().next().is_none());
+    }
+
+    #[test]
+    fn all_tuple_with_infallible_values_are_yielded_in_reverse() {
+        assert!(reverse_all::<(bool, Infallible)>().next().is_none());
+    }
+
+    #[test]
+    fn cardinality_equals_item_count_for_singleton() {
+        cardinality_equals_item_count::<(u8,)>();
+    }
+
+    #[test]
+    fn cardinality_equals_item_count_for_pair() {
+        cardinality_equals_item_count::<(u8, bool)>();
+    }
+
+    #[test]
+    fn cardinality_equals_item_count_for_triple() {
+        cardinality_equals_item_count::<(bool, u8, bool)>();
+    }
+
+    #[test]
+    fn cardinality_equals_item_count_for_option() {
+        cardinality_equals_item_count::<Option<u8>>();
+    }
+
+    #[test]
+    fn all_bool_option_items_are_yielded() {
+        assert!(all::<Option<bool>>().eq([None, Some(false), Some(true)]));
+    }
+
+    #[test]
+    fn all_bool_option_items_are_yielded_in_reverse() {
+        assert!(reverse_all::<Option<bool>>().eq([Some(true), Some(false), None]));
+    }
+
+    #[test]
+    fn all_infallible_option_items_are_yielded() {
+        assert!(all::<Option<Infallible>>().eq([None]));
+    }
+
+    #[test]
+    fn all_infallible_option_items_are_yielded_in_reverse() {
+        assert!(reverse_all::<Option<Infallible>>().eq([None]));
+    }
+
+    #[test]
+    fn cardinality_equals_item_count_for_ordering() {
+        cardinality_equals_item_count::<Ordering>();
+    }
+
+    #[test]
+    fn all_ordering_values_are_yielded() {
+        assert!(all::<Ordering>().eq([Ordering::Less, Ordering::Equal, Ordering::Greater]));
+    }
+
+    #[test]
+    fn all_ordering_values_are_yielded_in_reverse() {
+        assert!(reverse_all::<Ordering>().eq([Ordering::Greater, Ordering::Equal, Ordering::Less]));
+    }
+
+    #[test]
+    fn cardinality_equals_item_count_for_poll() {
+        cardinality_equals_item_count::<Poll<u8>>();
+    }
+
+    #[test]
+    fn all_bool_poll_items_are_yielded() {
+        assert!(all::<Poll<bool>>().eq([Poll::Ready(false), Poll::Ready(true), Poll::Pending]));
+    }
+
+    #[test]
+    fn all_bool_poll_items_are_yielded_in_reverse() {
+        assert!(reverse_all::<Poll<bool>>().eq([
+            Poll::Pending,
+            Poll::Ready(true),
+            Poll::Ready(false),
+        ]));
+    }
+
+    #[test]
+    fn all_infallible_poll_items_are_yielded() {
+        assert!(all::<Poll<Infallible>>().eq([Poll::Pending]));
+    }
+
+    #[test]
+    fn all_infallible_poll_items_are_yielded_in_reverse() {
+        assert!(reverse_all::<Poll<Infallible>>().eq([Poll::Pending]));
+    }
+
+    #[test]
+    fn tuple_fields_vary_from_right_to_left() {
+        assert!(all::<(Option<bool>, bool)>().eq([
+            (None, false),
+            (None, true),
+            (Some(false), false),
+            (Some(false), true),
+            (Some(true), false),
+            (Some(true), true),
+        ]));
+    }
+
+    #[test]
+    fn cardinality_of_empty_array_is_one() {
+        assert_eq!(cardinality::<[u8; 0]>(), 1);
+    }
+
+    #[test]
+    fn cardinality_equals_item_count_for_empty_array() {
+        cardinality_equals_item_count::<[u8; 0]>();
+    }
+
+    #[test]
+    fn cardinality_equals_item_count_for_array() {
+        cardinality_equals_item_count::<[u8; 3]>();
+    }
+
+    #[test]
+    fn array_items_vary_from_right_to_left() {
+        assert!(all::<[Option<bool>; 2]>().eq([
+            [None, None],
+            [None, Some(false)],
+            [None, Some(true)],
+            [Some(false), None],
+            [Some(false), Some(false)],
+            [Some(false), Some(true)],
+            [Some(true), None],
+            [Some(true), Some(false)],
+            [Some(true), Some(true)],
+        ]));
+    }
+
+    #[test]
+    fn all_empty_array_items_are_yielded() {
+        assert!(all::<[bool; 0]>().eq([[]]));
+    }
+
+    #[test]
+    fn cardinality_of_empty_infallible_array_is_one() {
+        assert_eq!(cardinality::<[Infallible; 0]>(), 1);
+    }
+
+    #[test]
+    fn cardinality_of_non_empty_infallible_array_is_zero() {
+        assert_eq!(cardinality::<[Infallible; 1]>(), 0);
+    }
+
+    #[test]
+    fn all_empty_infallible_array_items_are_yielded() {
+        assert!(all::<[Infallible; 0]>().eq([[]]));
+    }
+
+    #[test]
+    fn all_non_empty_infallible_array_items_are_yielded() {
+        assert!(all::<[Infallible; 1]>().next().is_none());
+    }
+}
diff --git a/tests/derive.rs b/tests/derive.rs
new file mode 100644 (file)
index 0000000..7b73c49
--- /dev/null
@@ -0,0 +1,183 @@
+// Copyright (c) 2018-2022 Stephane Raux. Distributed under the 0BSD license.
+
+use enum_iterator::{all, cardinality, reverse_all, Sequence};
+use std::{convert::Infallible, iter::once};
+
+#[derive(Clone, Copy, Debug, PartialEq, Sequence)]
+enum Direction {
+    North,
+    South,
+    West,
+    East,
+}
+
+#[derive(Clone, Debug, PartialEq, Sequence)]
+enum Either<L, R> {
+    Left(L),
+    Right(R),
+}
+
+#[test]
+fn all_values_of_generic_type_are_yielded() {
+    assert_eq!(cardinality::<Either<bool, Direction>>(), 6);
+    assert_eq!(
+        all::<Either<bool, Direction>>().collect::<Vec<_>>(),
+        [
+            Either::Left(false),
+            Either::Left(true),
+            Either::Right(Direction::North),
+            Either::Right(Direction::South),
+            Either::Right(Direction::West),
+            Either::Right(Direction::East),
+        ]
+    );
+}
+
+#[derive(Clone, Debug, PartialEq, Sequence)]
+struct Foo<T: Copy> {
+    x: T,
+}
+
+#[test]
+fn all_values_of_generic_type_with_trait_bound_are_yielded() {
+    assert_eq!(cardinality::<Foo<bool>>(), 2);
+    assert_eq!(
+        all::<Foo<bool>>().collect::<Vec<_>>(),
+        [Foo { x: false }, Foo { x: true }],
+    );
+}
+
+#[test]
+fn all_values_of_enum_type_with_empty_variant_are_yielded() {
+    assert_eq!(cardinality::<Either<Infallible, bool>>(), 2);
+    assert_eq!(
+        all::<Either<Infallible, bool>>().collect::<Vec<_>>(),
+        [Either::Right(false), Either::Right(true)],
+    );
+}
+
+#[derive(Debug, PartialEq, Sequence)]
+struct Impossible {
+    a: bool,
+    b: Infallible,
+}
+
+#[test]
+fn all_values_of_impossible_are_yielded() {
+    assert_eq!(cardinality::<Impossible>(), 0);
+    assert!(all::<Impossible>().next().is_none());
+}
+
+#[derive(Debug, PartialEq, Sequence)]
+enum Move {
+    Stay,
+    Basic(Direction),
+    Fancy(FancyMove),
+    Jump {
+        direction: Direction,
+        somersault: bool,
+    },
+    Swim(Direction, SwimmingStyle),
+}
+
+#[derive(Debug, PartialEq, Sequence)]
+struct FancyMove {
+    direction: Direction,
+    fast: bool,
+}
+
+#[derive(Debug, PartialEq, Sequence)]
+enum SwimmingStyle {
+    Breaststroke,
+    FrontCrawl,
+}
+
+fn all_moves() -> Vec<Move> {
+    let directions = [
+        Direction::North,
+        Direction::South,
+        Direction::West,
+        Direction::East,
+    ];
+    once(Move::Stay)
+        .chain(directions.into_iter().map(Move::Basic))
+        .chain(
+            directions
+                .into_iter()
+                .flat_map(|d| [(d, false), (d, true)])
+                .map(|(direction, fast)| FancyMove { direction, fast })
+                .map(Move::Fancy),
+        )
+        .chain(
+            directions
+                .into_iter()
+                .flat_map(|d| [(d, false), (d, true)])
+                .map(|(direction, somersault)| Move::Jump {
+                    direction,
+                    somersault,
+                }),
+        )
+        .chain(
+            directions
+                .into_iter()
+                .flat_map(|d| {
+                    [
+                        (d, SwimmingStyle::Breaststroke),
+                        (d, SwimmingStyle::FrontCrawl),
+                    ]
+                })
+                .map(|(direction, style)| Move::Swim(direction, style)),
+        )
+        .collect()
+}
+
+#[test]
+fn all_works() {
+    assert_eq!(all::<Move>().collect::<Vec<_>>(), all_moves());
+}
+
+#[test]
+fn reverse_all_works() {
+    let expected = {
+        let mut moves = all_moves();
+        moves.reverse();
+        moves
+    };
+    assert_eq!(reverse_all::<Move>().collect::<Vec<_>>(), expected);
+}
+
+#[derive(Debug, PartialEq, Sequence)]
+enum Empty {}
+
+#[test]
+fn empty_cadinality_is_zero() {
+    assert_eq!(cardinality::<Empty>(), 0);
+}
+
+#[test]
+fn all_values_of_empty_are_yielded() {
+    assert_eq!(all::<Empty>().collect::<Vec<_>>(), Vec::new());
+}
+
+#[test]
+fn all_values_of_empty_are_yielded_in_reverse() {
+    assert_eq!(reverse_all::<Empty>().collect::<Vec<_>>(), Vec::new());
+}
+
+#[derive(Debug, PartialEq, Sequence)]
+struct Unit;
+
+#[test]
+fn unit_cardinality_is_one() {
+    assert_eq!(cardinality::<Unit>(), 1);
+}
+
+#[test]
+fn all_values_of_unit_are_yielded() {
+    assert_eq!(all::<Unit>().collect::<Vec<_>>(), vec![Unit]);
+}
+
+#[test]
+fn all_values_of_unit_are_yielded_in_reverse() {
+    assert_eq!(reverse_all::<Unit>().collect::<Vec<_>>(), vec![Unit]);
+}