const_combinations/
lib.rs

1//! const fn combinations iter adapter
2//!
3//! # Examples
4//!
5//! ```
6//! use const_combinations::IterExt;
7//!
8//! let mut combinations = (1..5).combinations();
9//! assert_eq!(combinations.next(), Some([1, 2, 3]));
10//! assert_eq!(combinations.next(), Some([1, 2, 4]));
11//! assert_eq!(combinations.next(), Some([1, 3, 4]));
12//! assert_eq!(combinations.next(), Some([2, 3, 4]));
13//! assert_eq!(combinations.next(), None);
14//! ```
15
16#![no_std]
17#![feature(maybe_uninit_uninit_array)]
18
19extern crate alloc;
20
21mod combinations;
22mod permutations;
23
24pub use combinations::{Combinations, SliceCombinations};
25pub use permutations::{Permutations, SlicePermutations};
26
27/// An extension trait adding `combinations` and `permutations` to `Iterator`.
28pub trait IterExt: Iterator {
29    /// Return an iterator adaptor that iterates over the k-length combinations of
30    /// the elements from an iterator.
31    ///
32    /// The iterator produces a new array per iteration, and clones the iterator
33    /// elements. If `K` is greater than the length of the input iterator the
34    /// resulting iterator adaptor will yield no items.
35    ///
36    /// # Examples
37    ///
38    /// ```
39    /// use const_combinations::IterExt;
40    ///
41    /// let mut combinations = (1..5).combinations();
42    /// assert_eq!(combinations.next(), Some([1, 2, 3]));
43    /// assert_eq!(combinations.next(), Some([1, 2, 4]));
44    /// assert_eq!(combinations.next(), Some([1, 3, 4]));
45    /// assert_eq!(combinations.next(), Some([2, 3, 4]));
46    /// assert_eq!(combinations.next(), None);
47    /// ```
48    ///
49    /// Note: Combinations does not take into account the equality of the iterated values.
50    ///
51    /// ```
52    /// # use const_combinations::IterExt;
53    /// let mut combinations = vec![1, 2, 2].into_iter().combinations();
54    /// assert_eq!(combinations.next(), Some([1, 2])); // Note: these are the same
55    /// assert_eq!(combinations.next(), Some([1, 2])); // Note: these are the same
56    /// assert_eq!(combinations.next(), Some([2, 2]));
57    /// assert_eq!(combinations.next(), None);
58    /// ```
59    fn combinations<const K: usize>(self) -> Combinations<Self, K>
60    where
61        Self: Sized,
62        Self::Item: Clone,
63    {
64        Combinations::new(self)
65    }
66
67    /// Return an iterator adaptor that iterates over the k-length permutations of
68    /// the elements from an iterator.
69    ///
70    /// The iterator produces a new array per iteration, and clones the iterator
71    /// elements. If `K` is greater than the length of the input iterator the
72    /// resulting iterator adaptor will yield no items.
73    ///
74    /// # Examples
75    ///
76    /// ```
77    /// # use const_combinations::IterExt;
78    /// let mut permutations = (0..3).permutations();
79    /// assert_eq!(permutations.next(), Some([0, 1]));
80    /// assert_eq!(permutations.next(), Some([1, 0]));
81    /// assert_eq!(permutations.next(), Some([0, 2]));
82    /// assert_eq!(permutations.next(), Some([2, 0]));
83    /// assert_eq!(permutations.next(), Some([1, 2]));
84    /// assert_eq!(permutations.next(), Some([2, 1]));
85    /// assert_eq!(permutations.next(), None);
86    /// ```
87    ///
88    /// Note: Permutations does not take into account the equality of the iterated values.
89    ///
90    /// ```
91    /// # use const_combinations::IterExt;
92    /// let mut permutations = vec![2, 2].into_iter().permutations();
93    /// assert_eq!(permutations.next(), Some([2, 2])); // Note: these are the same
94    /// assert_eq!(permutations.next(), Some([2, 2])); // Note: these are the same
95    /// assert_eq!(permutations.next(), None);
96    /// ```
97    fn permutations<const K: usize>(self) -> Permutations<Self, K>
98    where
99        Self: Sized,
100        Self::Item: Clone,
101    {
102        Permutations::new(self)
103    }
104}
105
106impl<I> IterExt for I where I: Iterator {}
107
108/// An extension trait adding `combinations` and `permutations` to `Slice`.
109pub trait SliceExt<T> {
110    /// Return an iterator that iterates over the k-length combinations of
111    /// the elements from a slice.
112    ///
113    /// The iterator produces a new array per iteration, and returns references to the
114    /// elements of the slice. If `K` is greater than the length of the input slice the
115    /// resulting iterator will yield no items.
116    ///
117    /// # Examples
118    ///
119    /// ```
120    /// use const_combinations::SliceExt;
121    ///
122    /// let mut combinations = [1, 2, 3, 4].combinations();
123    /// assert_eq!(combinations.next(), Some([&1, &2, &3]));
124    /// assert_eq!(combinations.next(), Some([&1, &2, &4]));
125    /// assert_eq!(combinations.next(), Some([&1, &3, &4]));
126    /// assert_eq!(combinations.next(), Some([&2, &3, &4]));
127    /// assert_eq!(combinations.next(), None);
128    /// ```
129    ///
130    /// Note: Combinations does not take into account the equality of the slice elements.
131    ///
132    /// ```
133    /// # use const_combinations::SliceExt;
134    /// let mut combinations = [1, 2, 2].combinations();
135    /// assert_eq!(combinations.next(), Some([&1, &2])); // Note: these are the same
136    /// assert_eq!(combinations.next(), Some([&1, &2])); // Note: these are the same
137    /// assert_eq!(combinations.next(), Some([&2, &2]));
138    /// assert_eq!(combinations.next(), None);
139    /// ```
140    fn combinations<const K: usize>(&self) -> SliceCombinations<T, K>;
141
142    /// Return an iterator that iterates over the k-length permutations of
143    /// the elements from a slice.
144    ///
145    /// The iterator produces a new array per iteration, and clones the iterator
146    /// elements. If `K` is greater than the length of the input slice the
147    /// resulting iterator adaptor will yield no items.
148    ///
149    /// # Examples
150    ///
151    /// ```
152    /// # use const_combinations::SliceExt;
153    /// let mut permutations = [0, 1, 2].permutations();
154    /// assert_eq!(permutations.next(), Some([&0, &1]));
155    /// assert_eq!(permutations.next(), Some([&1, &0]));
156    /// assert_eq!(permutations.next(), Some([&0, &2]));
157    /// assert_eq!(permutations.next(), Some([&2, &0]));
158    /// assert_eq!(permutations.next(), Some([&1, &2]));
159    /// assert_eq!(permutations.next(), Some([&2, &1]));
160    /// assert_eq!(permutations.next(), None);
161    /// ```
162    ///
163    /// Note: Permutations does not take into account the equality of the slice elements.
164    ///
165    /// ```
166    /// # use const_combinations::SliceExt;
167    /// let mut permutations = [2, 2].permutations();
168    /// assert_eq!(permutations.next(), Some([&2, &2])); // Note: these are the same
169    /// assert_eq!(permutations.next(), Some([&2, &2])); // Note: these are the same
170    /// assert_eq!(permutations.next(), None);
171    /// ```
172    fn permutations<const K: usize>(&self) -> SlicePermutations<T, K>;
173}
174
175impl<T> SliceExt<T> for [T] {
176    fn combinations<const K: usize>(&self) -> SliceCombinations<T, K> {
177        SliceCombinations::new(self)
178    }
179    fn permutations<const K: usize>(&self) -> SlicePermutations<T, K> {
180        SlicePermutations::new(self)
181    }
182}
183
184fn make_array<T, F, const N: usize>(f: F) -> [T; N]
185where
186    F: Fn(usize) -> T,
187{
188    use core::mem::MaybeUninit;
189
190    // Create the result array based on the indices
191    let mut out: [MaybeUninit<T>; N] = MaybeUninit::uninit_array();
192
193    // NOTE: this clippy attribute can be removed once we can `collect` into `[usize; K]`.
194    #[allow(clippy::clippy::needless_range_loop)]
195    for i in 0..N {
196        out[i] = MaybeUninit::new(f(i));
197    }
198    unsafe { out.as_ptr().cast::<[T; N]>().read() }
199}