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}