uselesskey_core_jwks_order/
lib.rs1#![forbid(unsafe_code)]
2
3use core::fmt;
31
32pub trait HasKid {
34 fn kid(&self) -> &str;
36}
37
38#[derive(Clone)]
41pub struct KidSorted<T: HasKid> {
42 entries: Vec<Entry<T>>,
43}
44
45impl<T: HasKid> Default for KidSorted<T> {
46 fn default() -> Self {
47 Self {
48 entries: Vec::new(),
49 }
50 }
51}
52
53#[derive(Clone)]
54struct Entry<T: HasKid> {
55 kid: String,
56 index: usize,
57 value: T,
58}
59
60impl<T: HasKid + fmt::Debug> fmt::Debug for KidSorted<T> {
61 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
62 f.debug_struct("KidSorted")
63 .field("entries", &self.entries.len())
64 .finish_non_exhaustive()
65 }
66}
67
68impl<T: HasKid> KidSorted<T> {
69 pub fn new() -> Self {
71 Self::default()
72 }
73
74 pub fn push(&mut self, value: T) {
76 let index = self.entries.len();
77 let kid = value.kid().to_string();
78 self.entries.push(Entry { kid, index, value });
79 }
80
81 pub fn build(mut self) -> Vec<T> {
83 self.entries
84 .sort_by(|a, b| a.kid.cmp(&b.kid).then(a.index.cmp(&b.index)));
85 self.entries.into_iter().map(|e| e.value).collect()
86 }
87}
88
89#[cfg(test)]
90mod tests {
91 use super::{HasKid, KidSorted};
92
93 #[derive(Debug, Clone)]
94 struct TestItem {
95 kid: &'static str,
96 payload: &'static str,
97 }
98
99 impl HasKid for TestItem {
100 fn kid(&self) -> &str {
101 self.kid
102 }
103 }
104
105 #[test]
106 fn orders_items_by_kid() {
107 let mut sorter = KidSorted::new();
108 sorter.push(TestItem {
109 kid: "b",
110 payload: "second",
111 });
112 sorter.push(TestItem {
113 kid: "a",
114 payload: "first",
115 });
116 let items = sorter.build();
117 let order: Vec<_> = items.iter().map(|item| item.payload).collect();
118
119 assert_eq!(order, vec!["first", "second"]);
120 }
121
122 #[test]
123 fn preserves_insertion_for_equal_kids() {
124 let mut sorter = KidSorted::new();
125 sorter.push(TestItem {
126 kid: "dup",
127 payload: "one",
128 });
129 sorter.push(TestItem {
130 kid: "dup",
131 payload: "two",
132 });
133 sorter.push(TestItem {
134 kid: "dup",
135 payload: "three",
136 });
137
138 let items = sorter.build();
139 let order: Vec<_> = items.iter().map(|item| item.payload).collect();
140
141 assert_eq!(order, vec!["one", "two", "three"]);
142 }
143}