1use serde::{Deserialize, Serialize};
2
3#[derive(Copy, Clone, Debug, Default, PartialOrd, Serialize, Deserialize)]
9pub struct ObjectId {
10 value: Option<usize>,
11}
12
13impl ObjectId {
14 pub fn new(value: usize) -> Self {
16 ObjectId { value: Some(value) }
17 }
18}
19
20impl From<usize> for ObjectId {
21 fn from(value: usize) -> Self {
22 ObjectId::new(value)
23 }
24}
25
26impl PartialEq for ObjectId {
27 fn eq(&self, other: &Self) -> bool {
28 if let (Some(self_value), Some(other_value)) = (self.value, other.value) {
29 self_value == other_value
30 } else {
31 true
32 }
33 }
34}
35
36impl Eq for ObjectId {}
37
38pub struct ObjectIdGenerator {
43 next_id: usize,
44}
45
46impl ObjectIdGenerator {
47 pub fn new() -> Self {
49 Self { next_id: 1 }
50 }
51
52 pub fn next(&mut self) -> ObjectId {
54 let id = self.next_id;
55 self.next_id += 1;
56 ObjectId::new(id)
57 }
58}
59
60pub trait HaveDependencies {
65 fn depends_on(&self) -> &Vec<ObjectId>;
67 fn object_id(&self) -> ObjectId;
69}
70
71pub trait DependencySortable: Iterator {
73 fn sort_by_dependencies(self) -> Vec<Self::Item>;
78}
79
80impl<I> DependencySortable for I
81where
82 I: Iterator + Sized,
83 I::Item: HaveDependencies,
84{
85 fn sort_by_dependencies(self) -> Vec<Self::Item> {
86 let mut sorted: Vec<Self::Item> = self.collect();
87
88 if sorted.is_empty() {
89 return sorted;
90 }
91
92 let mut i = 0;
94 let mut j = sorted.len() - 1;
95 while i < j {
96 if sorted[i].depends_on().is_empty() {
97 i += 1;
98 } else if !sorted[j].depends_on().is_empty() {
99 j -= 1;
100 } else {
101 sorted.swap(i, j);
102 i += 1;
103 j -= 1;
104 }
105 }
106
107 let mut swaps = 0;
109 let max_swaps = sorted.len() * sorted.len();
110 loop {
111 let mut swapped = false;
112 for i in 0..sorted.len() {
113 for j in i + 1..sorted.len() {
114 if sorted[i].depends_on().contains(&sorted[j].object_id()) {
115 sorted.swap(i, j);
116 swapped = true;
117 swaps += 1;
118 }
119 }
120 }
121 if !swapped {
122 break;
123 }
124
125 if swaps > max_swaps {
126 panic!("Circular dependencies detected");
127 }
128 }
129
130 sorted
131 }
132}
133
134#[cfg(test)]
135mod tests {
136 use super::*;
137 use itertools::Itertools;
138 use std::fmt::{Debug, Formatter};
139 use std::panic::catch_unwind;
140
141 #[derive(Eq, Clone)]
142 struct TestItem {
143 object_id: ObjectId,
144 depends_on: Vec<ObjectId>,
145 }
146 impl HaveDependencies for TestItem {
147 fn depends_on(&self) -> &Vec<ObjectId> {
148 &self.depends_on
149 }
150
151 fn object_id(&self) -> ObjectId {
152 self.object_id
153 }
154 }
155
156 impl PartialEq for TestItem {
157 fn eq(&self, other: &Self) -> bool {
158 self.object_id == other.object_id
159 }
160 }
161
162 impl Debug for TestItem {
163 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
164 write!(f, "{}", self.object_id.value.unwrap())
165 }
166 }
167
168 #[test]
169 fn sorted_by_dependencies_1() {
170 let items = vec![
171 TestItem {
172 object_id: 1.into(),
173 depends_on: vec![],
174 },
175 TestItem {
176 object_id: 2.into(),
177 depends_on: vec![1.into()],
178 },
179 TestItem {
180 object_id: 3.into(),
181 depends_on: vec![1.into()],
182 },
183 ];
184
185 for items in items.into_iter().permutations(3) {
186 let sorted = items.into_iter().sort_by_dependencies();
187
188 assert!(matches!(sorted[0].object_id.value.unwrap(), 1));
189 assert!(matches!(sorted[1].object_id.value.unwrap(), 2 | 3));
190 assert!(matches!(sorted[2].object_id.value.unwrap(), 2 | 3));
191 }
192 }
193
194 #[test]
195 fn sorted_by_dependencies_2() {
196 let items = vec![
197 TestItem {
198 object_id: 1.into(),
199 depends_on: vec![3.into()],
200 },
201 TestItem {
202 object_id: 2.into(),
203 depends_on: vec![],
204 },
205 TestItem {
206 object_id: 3.into(),
207 depends_on: vec![],
208 },
209 ];
210
211 for items in items.into_iter().permutations(3) {
212 let sorted = items.into_iter().sort_by_dependencies();
213
214 assert!(matches!(sorted[0].object_id.value.unwrap(), 2 | 3));
215 assert!(matches!(sorted[1].object_id.value.unwrap(), 2 | 3));
216 assert!(matches!(sorted[2].object_id.value.unwrap(), 1));
217 }
218 }
219
220 #[test]
221 fn sorted_by_dependencies_3() {
222 let items = vec![
223 TestItem {
224 object_id: 1.into(),
225 depends_on: vec![3.into()],
226 },
227 TestItem {
228 object_id: 2.into(),
229 depends_on: vec![],
230 },
231 TestItem {
232 object_id: 3.into(),
233 depends_on: vec![2.into()],
234 },
235 ];
236
237 for items in items.into_iter().permutations(3) {
238 let sorted = items.into_iter().sort_by_dependencies();
239
240 assert!(matches!(sorted[0].object_id.value.unwrap(), 2));
241 assert!(matches!(sorted[1].object_id.value.unwrap(), 3));
242 assert!(matches!(sorted[2].object_id.value.unwrap(), 1));
243 }
244 }
245
246 #[test]
247 fn sorted_by_dependencies_4() {
248 let items = vec![
249 TestItem {
250 object_id: 1.into(),
251 depends_on: vec![3.into(), 2.into()],
252 },
253 TestItem {
254 object_id: 2.into(),
255 depends_on: vec![],
256 },
257 TestItem {
258 object_id: 3.into(),
259 depends_on: vec![2.into()],
260 },
261 ];
262
263 for items in items.into_iter().permutations(3) {
264 let sorted = items.into_iter().sort_by_dependencies();
265
266 assert!(matches!(sorted[0].object_id.value.unwrap(), 2));
267 assert!(matches!(sorted[1].object_id.value.unwrap(), 3));
268 assert!(matches!(sorted[2].object_id.value.unwrap(), 1));
269 }
270 }
271
272 #[test]
273 fn circular_dependencies() {
274 let result = catch_unwind(|| {
275 let items = vec![
276 TestItem {
277 object_id: 1.into(),
278 depends_on: vec![3.into()],
279 },
280 TestItem {
281 object_id: 2.into(),
282 depends_on: vec![1.into()],
283 },
284 TestItem {
285 object_id: 3.into(),
286 depends_on: vec![2.into()],
287 },
288 ];
289
290 items.into_iter().sort_by_dependencies();
291 });
292
293 assert!(result.is_err());
294 }
295
296 #[test]
297 fn handles_empty_input() {
298 let items: Vec<TestItem> = vec![];
299 let sorted = items.into_iter().sort_by_dependencies();
300 assert_eq!(sorted, vec![]);
301 }
302
303 #[test]
304 fn handles_single_item_input() {
305 let items: Vec<TestItem> = vec![TestItem {
306 object_id: 1.into(),
307 depends_on: vec![],
308 }];
309 let sorted = items.into_iter().sort_by_dependencies();
310 assert_eq!(
311 sorted,
312 vec![TestItem {
313 object_id: 1.into(),
314 depends_on: vec![],
315 },]
316 );
317 }
318}