///|
priv struct ComponentFilter {
id : ComponentId
matches : (Component) -> Bool
}
///|
struct QueryFilter {
required : Array[ComponentFilter]
forbidden : Array[ComponentFilter]
}
///|
pub fn QueryFilter::QueryFilter() -> Self {
{ required: [], forbidden: [] }
}
///|
pub fn[C : ComponentValue] QueryFilter::with_component(
self : Self,
_hint? : C? = None,
) -> Self {
let required = self.required.copy()
required.push({
id: C::component_id(),
matches: fn(component) { C::from_component(component) is Some(_) },
})
{ required, forbidden: self.forbidden.copy() }
}
///|
pub fn[C : ComponentValue] QueryFilter::without_component(
self : Self,
_hint? : C? = None,
) -> Self {
let forbidden = self.forbidden.copy()
forbidden.push({
id: C::component_id(),
matches: fn(component) { C::from_component(component) is Some(_) },
})
{ required: self.required.copy(), forbidden }
}
///|
pub fn QueryFilter::is_empty(self : Self) -> Bool {
self.required.length() == 0 && self.forbidden.length() == 0
}
///|
fn World::entity_matches_filter(
self : World,
entity : EntityId,
filter : QueryFilter,
) -> Bool {
guard !filter.is_empty() else { return true }
for required in filter.required {
match self.component_store(required.id) {
Some(store) =>
match store.get(entity) {
Some(component) => if !(required.matches)(component) { return false }
None => return false
}
None => return false
}
}
for forbidden in filter.forbidden {
match self.component_store(forbidden.id) {
Some(store) =>
match store.get(entity) {
Some(component) => if (forbidden.matches)(component) { return false }
None => ()
}
None => ()
}
}
true
}
///|
fn World::entity_matches_filter_with_driver(
self : World,
entity : EntityId,
filter : QueryFilter,
driver_id : ComponentId,
driver_component : Component,
) -> Bool {
guard !filter.is_empty() else { return true }
for required in filter.required {
if required.id == driver_id {
if !(required.matches)(driver_component) {
return false
}
} else {
match self.component_store(required.id) {
Some(store) =>
match store.get(entity) {
Some(component) =>
if !(required.matches)(component) {
return false
}
None => return false
}
None => return false
}
}
}
for forbidden in filter.forbidden {
if forbidden.id == driver_id {
if (forbidden.matches)(driver_component) {
return false
}
} else {
match self.component_store(forbidden.id) {
Some(store) =>
match store.get(entity) {
Some(component) =>
if (forbidden.matches)(component) {
return false
}
None => ()
}
None => ()
}
}
}
true
}
///|
fn QueryFilter::shortest_required_id(
self : Self,
world : World,
current_id : ComponentId,
current_len : Int,
) -> ComponentId {
let mut selected_id = current_id
let mut selected_len = current_len
for required in self.required {
let required_len = world.component_store_len(required.id)
if required_len < selected_len {
selected_id = required.id
selected_len = required_len
}
}
selected_id
}
///|
fn[V] World::filter_entity_rows(
self : World,
rows : Iter2[EntityId, V],
filter : QueryFilter,
) -> Iter2[EntityId, V] {
if filter.is_empty() {
rows
} else {
Iter2::new(fn() -> (EntityId, V)? {
for ;; {
match rows.next() {
None => break None
Some((entity, value)) =>
if self.entity_matches_filter(entity, filter) {
break Some((entity, value))
} else {
continue
}
}
}
})
}
}
///|
fn[V] values_from_entity_rows(rows : Iter2[EntityId, V]) -> Iter[V] {
rows
.iter()
.map(fn(row) {
let (_entity, value) = row
value
})
}