1#![no_std]
2
3#[doc(hidden)]
27pub use arrayvec_const::ArrayVec;
28
29#[macro_export]
61macro_rules! const_quicksort {
62 ($data:expr) => {{
63 macro_rules! cmp {
64 ($a:expr, $b:expr) => {{ $a < $b }};
65 }
66 $crate::const_quicksort_adv!($data, cmp)
67 }};
68 ($data:expr, |$a:ident, $b:ident| $cmp:expr) => {{
69 macro_rules! cmp {
70 ($a_:expr, $b_:expr) => {{
71 let ($a, $b) = (&$a_, &$b_);
72 $cmp
73 }};
74 }
75 $crate::const_quicksort_adv!($data, cmp)
76 }};
77 ($data:expr, $cmp:expr) => {{
78 macro_rules! cmp {
79 ($a:expr, $b:expr) => {{ $cmp(&$a, &$b) }};
80 }
81 $crate::const_quicksort_adv!($data, cmp)
82 }};
83}
84
85
86#[macro_export]
92macro_rules! const_quicksort_adv {
93 ($data:expr, $cmp:path) => {{
94 use core::mem::forget;
95
96 struct Wrapper<T>(T);
97 impl<T, const N: usize> Wrapper<[T; N]> {
98 #[allow(unused)]
99 const fn as_mut_slice(&mut self) -> &mut [T] {
100 &mut self.0
101 }
102 }
103 impl<'a, T> Wrapper<&'a mut [T]> {
104 #[allow(unused)]
105 const fn as_mut_slice(&mut self) -> &mut [T] {
106 self.0
107 }
108 }
109 impl<'a, T, const N: usize> Wrapper<&'a mut [T; N]> {
110 #[allow(unused)]
111 const fn as_mut_slice(&mut self) -> &mut [T] {
112 self.0
113 }
114 }
115
116 let mut data = Wrapper($data);
117 let mut slices = $crate::ArrayVec::<&mut [_], 64>::new();
119 let Ok(()) = slices.try_push(data.as_mut_slice()) else { panic!("ran out of capacity") };
120 while let Some(data) = slices.pop() {
121 match data.len() {
122 0 | 1 => continue,
123 2 => {
124 if !{$cmp!(data[0], data[1])} {
125 data.swap(0, 1);
126 }
127 continue;
128 },
129 _ => {}
130 }
131
132
133 let (pivot, rest) = data
134 .split_first_mut()
135 .expect("slice is not empty, as verified above");
136
137 let mut left = 0;
138 let mut right = rest.len() - 1;
139 while left <= right {
140 if {$cmp!(rest[left], *pivot)} {
141 left += 1;
142 } else if !{$cmp!(rest[right], *pivot)} {
143 if right == 0 {
144 break;
145 }
146 right -= 1;
147 } else {
148 rest.swap(left, right);
149 left += 1;
150 if right == 0 {
151 break;
152 }
153 right -= 1;
154 }
155 }
156
157 data.swap(0, left);
158 let (left, right) = data.split_at_mut(left);
159 let Ok(()) = slices.try_push(left) else { panic!("ran out of capacity") };
160 if let Some((_pivot, right)) = right.split_first_mut() {
161 let Ok(()) = slices.try_push(right) else { panic!("ran out of capacity") };
162 }
163 }
164 forget(slices);
165
166 data.0
167 }};
168}
169
170#[cfg(test)]
171mod test {
172 #[derive(Debug)]
173 struct Foo(u8);
174
175 const fn lt(a: &u8, b: &u8) -> bool {
176 *a < *b
177 }
178
179 const U8S: &[u8] = &const_quicksort!([3, 2, 1]);
180 const U8S_FN: &[u8] = &const_quicksort!([3, 2, 1], lt);
181 const FOOS: &[Foo] = &const_quicksort!([Foo(1), Foo(2), Foo(4), Foo(3)], |a, b| a.0 > b.0);
182 const FOOS_MUT_REF: &[Foo] = &{
183 let mut foo = [Foo(1), Foo(2), Foo(4), Foo(3)];
184 const_quicksort!(foo.split_last_mut().expect("failed").1, |a, b| a.0 > b.0);
185 foo
186 };
187
188 #[test]
189 fn test_u8() {
190 assert_eq!(U8S, [1, 2, 3]);
191 }
192
193 #[test]
194 fn test_u8_fn() {
195 assert_eq!(U8S_FN, [1, 2, 3]);
196 }
197
198 #[test]
199 fn test_foo() {
200 assert!(FOOS.iter().map(|v| v.0).eq([4, 3, 2, 1]));
201 assert!(FOOS_MUT_REF.iter().map(|v| v.0).eq([4, 2, 1, 3]));
202 }
203}