use core::fmt::Debug;
use unlit_ecs::Entity;
pub(crate) trait OrderKey: Copy + Ord + Debug {
const ORDER: &'static str;
const SUBJECT: &'static str;
fn value(self) -> i32;
}
pub(crate) type AmbiguousGroup<K> = (K, Vec<Entity>);
#[derive(Debug)]
pub(crate) struct Ordering<K: OrderKey> {
keys: Vec<(K, Entity)>,
order: Vec<Entity>,
ambiguous: Vec<AmbiguousGroup<K>>,
}
impl<K: OrderKey> Default for Ordering<K> {
fn default() -> Self {
Self {
keys: Vec::new(),
order: Vec::new(),
ambiguous: Vec::new(),
}
}
}
impl<K: OrderKey> Ordering<K> {
pub(crate) fn resolve(&mut self, keys: impl IntoIterator<Item = (K, Entity)>) {
self.keys.clear();
self.keys.extend(keys);
self.keys
.sort_unstable_by_key(|(order, entity)| (*order, *entity));
self.order.clear();
self.ambiguous.clear();
let mut start = 0;
while start < self.keys.len() {
let order = self.keys[start].0;
let mut end = start + 1;
while end < self.keys.len() && self.keys[end].0 == order {
end += 1;
}
if end - start > 1 {
let group = self.keys[start..end]
.iter()
.map(|(_, entity)| *entity)
.collect();
self.ambiguous.push((order, group));
}
start = end;
}
self.order
.extend(self.keys.iter().map(|(_, entity)| *entity));
}
#[cfg(test)]
pub(crate) fn order_capacity(&self) -> usize {
self.order.capacity()
}
#[cfg(test)]
pub(crate) fn ambiguous_capacity(&self) -> usize {
self.ambiguous.capacity()
}
pub(crate) fn entities(&self) -> &[Entity] {
&self.order
}
pub(crate) fn ambiguous(&self) -> &[AmbiguousGroup<K>] {
&self.ambiguous
}
}
#[derive(Debug)]
pub(crate) struct OrderWarnings<K: OrderKey> {
reported: Vec<(Option<Entity>, Vec<AmbiguousGroup<K>>)>,
}
impl<K: OrderKey> Default for OrderWarnings<K> {
fn default() -> Self {
Self {
reported: Vec::new(),
}
}
}
impl<K: OrderKey> OrderWarnings<K> {
pub(crate) fn check(&mut self, ambiguous: &[AmbiguousGroup<K>]) -> bool {
self.report(None, ambiguous)
}
pub(crate) fn check_for(&mut self, owner: Entity, ambiguous: &[AmbiguousGroup<K>]) -> bool {
self.report(Some(owner), ambiguous)
}
pub(crate) fn retain_owners(&mut self, live: &[Entity]) {
self.reported.retain(|(owner, _)| match owner {
None => true,
Some(owner) => live.contains(owner),
});
}
fn report(&mut self, owner: Option<Entity>, ambiguous: &[AmbiguousGroup<K>]) -> bool {
let index = match self.reported.iter().position(|(held, _)| *held == owner) {
Some(index) => index,
None => {
self.reported.push((owner, Vec::new()));
self.reported.len() - 1
}
};
let reported = &mut self.reported[index].1;
if reported.as_slice() == ambiguous {
return false;
}
for (order, group) in ambiguous {
log::warn!(
"{} {} declared the same {}({}): entities {:?}; recording them in an unspecified order — give them distinct orders to choose explicitly",
group.len(),
K::SUBJECT,
K::ORDER,
order.value(),
group,
);
}
reported.clear();
reported.extend_from_slice(ambiguous);
!ambiguous.is_empty()
}
}