fj_core/objects/
object_set.rs1use std::{collections::BTreeSet, fmt::Debug, iter, slice, vec};
2
3use itertools::Itertools;
4
5use crate::storage::{Handle, HandleWrapper};
6
7#[derive(Clone, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)]
13pub struct ObjectSet<T> {
14 inner: Vec<HandleWrapper<T>>,
23}
24
25impl<T> ObjectSet<T> {
26 pub fn new(
32 handles: impl IntoIterator<Item = impl Into<HandleWrapper<T>>>,
33 ) -> Self
34 where
35 T: Debug + Ord,
36 {
37 let mut added = BTreeSet::new();
38 let mut inner = Vec::new();
39
40 let handles = handles.into_iter().map(|handle| handle.into());
41
42 for handle in handles {
43 if added.contains(&handle) {
44 panic!(
45 "Constructing `ObjectSet` with duplicate handle: {:?}",
46 handle
47 );
48 }
49
50 added.insert(handle.clone());
51 inner.push(handle);
52 }
53
54 Self { inner }
55 }
56
57 pub fn len(&self) -> usize {
59 self.inner.len()
60 }
61
62 pub fn is_empty(&self) -> bool {
64 self.inner.is_empty()
65 }
66
67 pub fn contains(&self, object: &Handle<T>) -> bool {
69 self.index_of(object).is_some()
70 }
71
72 pub fn only(&self) -> &Handle<T> {
78 let mut iter = self.inner.iter();
79 let item = iter
80 .next()
81 .expect("Requested only item, but no items available");
82
83 assert!(
84 iter.next().is_none(),
85 "Requested only item, but more than one available"
86 );
87
88 item
89 }
90
91 pub fn first(&self) -> &Handle<T> {
97 self.inner
98 .first()
99 .expect("Requested first item, but no items available")
100 }
101
102 pub fn nth(&self, index: usize) -> Option<&Handle<T>> {
104 self.inner.get(index).map(|wrapper| &wrapper.0)
105 }
106
107 pub fn nth_circular(&self, index: usize) -> &Handle<T> {
116 assert!(!self.is_empty(), "`ObjectSet` must not be empty");
117
118 let index = index % self.len();
119 self.nth(index)
120 .expect("Index must be valid, due to modulo above")
121 }
122
123 pub fn index_of(&self, handle: &Handle<T>) -> Option<usize> {
125 self.inner.iter().position(|h| h.id() == handle.id())
126 }
127
128 pub fn after(&self, handle: &Handle<T>) -> Option<&Handle<T>> {
132 self.index_of(handle)
133 .map(|index| self.nth_circular(index + 1))
134 }
135
136 pub fn iter(&self) -> ObjectSetIter<T> {
138 self.inner.iter().map(HandleWrapper::as_handle)
139 }
140
141 pub fn pairs(&self) -> impl Iterator<Item = (&Handle<T>, &Handle<T>)> {
143 self.iter().circular_tuple_windows()
144 }
145
146 #[must_use]
154 pub fn replace(
155 &self,
156 original: &Handle<T>,
157 replacements: impl IntoIterator<Item = impl Into<Handle<T>>>,
158 ) -> Option<Self>
159 where
160 T: Debug + Ord,
161 {
162 let mut iter = self.iter().cloned().peekable();
163
164 let mut before = Vec::new();
166 loop {
167 let next = match iter.next() {
168 Some(handle) => handle,
169 None => {
170 return None;
173 }
174 };
175
176 if next.id() == original.id() {
177 break;
178 }
179
180 before.push(next.clone());
181 }
182
183 let after = iter;
186
187 Some(
188 before
189 .into_iter()
190 .chain(replacements.into_iter().map(|handle| handle.into()))
191 .chain(after)
192 .collect(),
193 )
194 }
195}
196
197impl<O> FromIterator<Handle<O>> for ObjectSet<O>
198where
199 O: Debug + Ord,
200{
201 fn from_iter<T: IntoIterator<Item = Handle<O>>>(handles: T) -> Self {
202 Self::new(handles)
203 }
204}
205
206impl<'r, T> IntoIterator for &'r ObjectSet<T> {
207 type Item = &'r Handle<T>;
208 type IntoIter = ObjectSetIter<'r, T>;
209
210 fn into_iter(self) -> Self::IntoIter {
211 self.iter()
212 }
213}
214
215impl<T> IntoIterator for ObjectSet<T> {
216 type Item = Handle<T>;
217 type IntoIter = ObjectSetIntoIter<T>;
218
219 fn into_iter(self) -> Self::IntoIter {
220 self.inner.into_iter().map(HandleWrapper::into_handle)
221 }
222}
223
224pub type ObjectSetIter<'r, T> = iter::Map<
228 slice::Iter<'r, HandleWrapper<T>>,
229 fn(&HandleWrapper<T>) -> &Handle<T>,
230>;
231
232pub type ObjectSetIntoIter<T> = iter::Map<
243 vec::IntoIter<HandleWrapper<T>>,
244 fn(HandleWrapper<T>) -> Handle<T>,
245>;
246
247#[cfg(test)]
248mod tests {
249 use std::collections::HashSet;
250
251 use crate::{
252 objects::Cycle, operations::insert::Insert, storage::HandleWrapper,
253 Core,
254 };
255
256 use super::ObjectSet;
257
258 #[test]
259 fn equal_but_not_identical_objects() {
260 let mut core = Core::new();
261
262 let bare_cycle = Cycle::new([]);
263 let cycle_a = bare_cycle.clone().insert(&mut core);
264 let cycle_b = bare_cycle.insert(&mut core);
265
266 let _object_set = ObjectSet::new([cycle_a, cycle_b]);
267 }
270
271 #[test]
272 fn object_set_from_handle_wrappers() {
273 let mut core = Core::new();
274
275 let bare_cycle = Cycle::new([]);
276 let cycle_a = HandleWrapper::from(bare_cycle.clone().insert(&mut core));
277 let cycle_b = HandleWrapper::from(bare_cycle.insert(&mut core));
278
279 let _object_set = ObjectSet::new([cycle_a, cycle_b]);
280 }
281
282 #[test]
283 fn object_set_from_deduplicated_hash_set() {
284 let mut core = Core::new();
285
286 let bare_cycle = Cycle::new([]);
287 let cycle_a = HandleWrapper::from(bare_cycle.clone().insert(&mut core));
288 let cycle_b = HandleWrapper::from(bare_cycle.insert(&mut core));
289
290 let _object_set = ObjectSet::new(HashSet::from([cycle_a, cycle_b]));
291 }
292}