use std::{collections::BTreeSet, fmt::Debug, iter, slice, vec};
use itertools::Itertools;
use crate::storage::{Handle, HandleWrapper};
#[derive(Clone, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)]
pub struct ObjectSet<T> {
inner: Vec<HandleWrapper<T>>,
}
impl<T> ObjectSet<T> {
pub fn new(
handles: impl IntoIterator<Item = impl Into<HandleWrapper<T>>>,
) -> Self
where
T: Debug + Ord,
{
let mut added = BTreeSet::new();
let mut inner = Vec::new();
let handles = handles.into_iter().map(|handle| handle.into());
for handle in handles {
if added.contains(&handle) {
panic!(
"Constructing `ObjectSet` with duplicate handle: {:?}",
handle
);
}
added.insert(handle.clone());
inner.push(handle);
}
Self { inner }
}
pub fn len(&self) -> usize {
self.inner.len()
}
pub fn is_empty(&self) -> bool {
self.inner.is_empty()
}
pub fn contains(&self, object: &Handle<T>) -> bool {
self.index_of(object).is_some()
}
pub fn only(&self) -> &Handle<T> {
let mut iter = self.inner.iter();
let item = iter
.next()
.expect("Requested only item, but no items available");
assert!(
iter.next().is_none(),
"Requested only item, but more than one available"
);
item
}
pub fn first(&self) -> &Handle<T> {
self.inner
.first()
.expect("Requested first item, but no items available")
}
pub fn nth(&self, index: usize) -> Option<&Handle<T>> {
self.inner.get(index).map(|wrapper| &wrapper.0)
}
pub fn nth_circular(&self, index: usize) -> &Handle<T> {
assert!(!self.is_empty(), "`ObjectSet` must not be empty");
let index = index % self.len();
self.nth(index)
.expect("Index must be valid, due to modulo above")
}
pub fn index_of(&self, handle: &Handle<T>) -> Option<usize> {
self.inner.iter().position(|h| h.id() == handle.id())
}
pub fn after(&self, handle: &Handle<T>) -> Option<&Handle<T>> {
self.index_of(handle)
.map(|index| self.nth_circular(index + 1))
}
pub fn iter(&self) -> ObjectSetIter<T> {
self.inner.iter().map(HandleWrapper::as_handle)
}
pub fn pairs(&self) -> impl Iterator<Item = (&Handle<T>, &Handle<T>)> {
self.iter().circular_tuple_windows()
}
#[must_use]
pub fn replace(
&self,
original: &Handle<T>,
replacements: impl IntoIterator<Item = impl Into<Handle<T>>>,
) -> Option<Self>
where
T: Debug + Ord,
{
let mut iter = self.iter().cloned().peekable();
let mut before = Vec::new();
loop {
let next = match iter.next() {
Some(handle) => handle,
None => {
return None;
}
};
if next.id() == original.id() {
break;
}
before.push(next.clone());
}
let after = iter;
Some(
before
.into_iter()
.chain(replacements.into_iter().map(|handle| handle.into()))
.chain(after)
.collect(),
)
}
}
impl<O> FromIterator<Handle<O>> for ObjectSet<O>
where
O: Debug + Ord,
{
fn from_iter<T: IntoIterator<Item = Handle<O>>>(handles: T) -> Self {
Self::new(handles)
}
}
impl<'r, T> IntoIterator for &'r ObjectSet<T> {
type Item = &'r Handle<T>;
type IntoIter = ObjectSetIter<'r, T>;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
impl<T> IntoIterator for ObjectSet<T> {
type Item = Handle<T>;
type IntoIter = ObjectSetIntoIter<T>;
fn into_iter(self) -> Self::IntoIter {
self.inner.into_iter().map(HandleWrapper::into_handle)
}
}
pub type ObjectSetIter<'r, T> = iter::Map<
slice::Iter<'r, HandleWrapper<T>>,
fn(&HandleWrapper<T>) -> &Handle<T>,
>;
pub type ObjectSetIntoIter<T> = iter::Map<
vec::IntoIter<HandleWrapper<T>>,
fn(HandleWrapper<T>) -> Handle<T>,
>;
#[cfg(test)]
mod tests {
use std::collections::HashSet;
use crate::{
objects::Cycle, operations::insert::Insert, storage::HandleWrapper,
Core,
};
use super::ObjectSet;
#[test]
fn equal_but_not_identical_objects() {
let mut core = Core::new();
let bare_cycle = Cycle::new([]);
let cycle_a = bare_cycle.clone().insert(&mut core);
let cycle_b = bare_cycle.insert(&mut core);
let _object_set = ObjectSet::new([cycle_a, cycle_b]);
}
#[test]
fn object_set_from_handle_wrappers() {
let mut core = Core::new();
let bare_cycle = Cycle::new([]);
let cycle_a = HandleWrapper::from(bare_cycle.clone().insert(&mut core));
let cycle_b = HandleWrapper::from(bare_cycle.insert(&mut core));
let _object_set = ObjectSet::new([cycle_a, cycle_b]);
}
#[test]
fn object_set_from_deduplicated_hash_set() {
let mut core = Core::new();
let bare_cycle = Cycle::new([]);
let cycle_a = HandleWrapper::from(bare_cycle.clone().insert(&mut core));
let cycle_b = HandleWrapper::from(bare_cycle.insert(&mut core));
let _object_set = ObjectSet::new(HashSet::from([cycle_a, cycle_b]));
}
}