const_str/__ctfe/
sorted.rs

1const fn str_clone<'a, const N: usize>(ss: &[&'a str]) -> [&'a str; N] {
2    assert!(ss.len() == N);
3    let mut buf = [""; N];
4    let mut i = 0;
5    while i < ss.len() {
6        buf[i] = ss[i];
7        i += 1;
8    }
9    buf
10}
11
12const fn str_sorted<'a, const N: usize>(ss: &[&'a str]) -> [&'a str; N] {
13    let mut buf = str_clone(ss);
14
15    let mut l = N;
16    while l > 1 {
17        let mut swapped = false;
18
19        let mut i = 0;
20        while i < l - 1 {
21            let (lhs, rhs) = (buf[i], buf[i + 1]);
22            if crate::compare!(>, lhs, rhs) {
23                (buf[i], buf[i + 1]) = (rhs, lhs);
24                swapped = true;
25            }
26            i += 1;
27        }
28
29        if !swapped {
30            break;
31        }
32
33        l -= 1;
34    }
35
36    buf
37}
38
39pub struct Sorted<T>(pub T);
40
41impl<'a> Sorted<&[&'a str]> {
42    pub const fn output_len(&self) -> usize {
43        self.0.len()
44    }
45
46    pub const fn const_eval<const N: usize>(&self) -> [&'a str; N] {
47        str_sorted(self.0)
48    }
49}
50
51impl<'a, const L: usize> Sorted<[&'a str; L]> {
52    pub const fn output_len(&self) -> usize {
53        L
54    }
55
56    pub const fn const_eval(&self) -> [&'a str; L] {
57        str_sorted(&self.0)
58    }
59}
60
61impl<'a, const L: usize> Sorted<&[&'a str; L]> {
62    pub const fn output_len(&self) -> usize {
63        L
64    }
65
66    pub const fn const_eval(&self) -> [&'a str; L] {
67        str_sorted(self.0)
68    }
69}
70
71/// Sorts string slices and returns a new array.
72///
73/// The input type must be one of:
74/// + [`&[&str]`](slice)
75/// + [`[&str; N]`](array)
76/// + [`&[&str; N]`](array)
77///
78/// This macro is [const-context only](./index.html#const-context-only).
79///
80/// # Examples
81///
82/// ```rust
83/// const SORTED1: &[&str] = &const_str::sorted!(["one", "two", "three"]);
84/// assert_eq!(SORTED1, &["one", "three", "two"]);
85///
86/// const SORTED2: [&str; 3] = const_str::sorted!(["1", "2", "10"]);
87/// assert_eq!(SORTED2, ["1", "10", "2"]);
88/// ```
89///
90#[macro_export]
91macro_rules! sorted {
92    ($s:expr) => {{
93        const N: usize = $crate::__ctfe::Sorted($s).output_len();
94        const SS: [&str; N] = $crate::__ctfe::Sorted($s).const_eval();
95        SS
96    }};
97}
98
99#[cfg(test)]
100mod tests {
101    fn std_sorted<'a>(iter: impl IntoIterator<Item = &'a str>) -> Vec<&'a str> {
102        let mut v: Vec<_> = iter.into_iter().collect();
103        v.sort_unstable();
104        v
105    }
106
107    #[test]
108    fn test_sorted() {
109        macro_rules! testcase {
110            ($s:expr) => {
111                let const_sorted = sorted!($s);
112                let std_sorted = std_sorted($s);
113                assert_eq!(const_sorted, &*std_sorted);
114            };
115        }
116
117        testcase!([]);
118        testcase!(["a"]);
119        testcase!(["a", "a"]);
120        testcase!(["b", "a"]);
121        testcase!(["a", "b", "c"]);
122        testcase!(["b", "a", "c"]);
123        testcase!(["c", "b", "a"]);
124        testcase!(["1", "2", "10", "20", "3"]);
125    }
126}