use crate::world::unsafe_world_cell::UnsafeWorldCell;
use crate::{component::ComponentId, resource::IS_RESOURCE};
use alloc::{format, string::String, vec, vec::Vec};
use core::iter::FusedIterator;
use core::{fmt, fmt::Debug};
use derive_more::From;
use fixedbitset::{Difference, FixedBitSet, Intersection, IntoOnes, Ones, Union};
use thiserror::Error;
#[derive(Eq, PartialEq, Default, Hash, Debug)]
pub struct Access {
read_and_writes: ComponentIdSet,
writes: ComponentIdSet,
read_and_writes_inverted: bool,
writes_inverted: bool,
archetypal: ComponentIdSet,
}
impl Clone for Access {
fn clone(&self) -> Self {
Self {
read_and_writes: self.read_and_writes.clone(),
writes: self.writes.clone(),
read_and_writes_inverted: self.read_and_writes_inverted,
writes_inverted: self.writes_inverted,
archetypal: self.archetypal.clone(),
}
}
fn clone_from(&mut self, source: &Self) {
self.read_and_writes.clone_from(&source.read_and_writes);
self.writes.clone_from(&source.writes);
self.read_and_writes_inverted = source.read_and_writes_inverted;
self.writes_inverted = source.writes_inverted;
self.archetypal.clone_from(&source.archetypal);
}
}
impl Access {
pub const fn new() -> Self {
Self {
read_and_writes_inverted: false,
writes_inverted: false,
read_and_writes: ComponentIdSet::new(),
writes: ComponentIdSet::new(),
archetypal: ComponentIdSet::new(),
}
}
pub(crate) const fn new_read_all() -> Self {
let mut access = Self::new();
access.read_and_writes_inverted = true;
access
}
pub(crate) const fn new_write_all() -> Self {
let mut access = Self::new();
access.read_and_writes_inverted = true;
access.writes_inverted = true;
access
}
#[deprecated(since = "0.19.0", note = "use Access::add_read")]
pub fn add_component_read(&mut self, index: ComponentId) {
self.add_read(index);
}
pub fn add_read(&mut self, index: ComponentId) {
if !self.read_and_writes_inverted {
self.read_and_writes.insert(index);
} else {
self.read_and_writes.remove(index);
}
}
#[deprecated(since = "0.19.0", note = "use Access::add_write")]
pub fn add_component_write(&mut self, index: ComponentId) {
self.add_write(index);
}
pub fn add_write(&mut self, index: ComponentId) {
self.add_read(index);
if !self.writes_inverted {
self.writes.insert(index);
} else {
self.writes.remove(index);
}
}
#[deprecated(
since = "0.19.0",
note = "Call `FilteredAccessSet::add_resource_read`. If this is called in a `WorldQuery` impl, then you will need to implement `init_nested_access` to modify the `FilteredAccessSet`."
)]
pub fn add_resource_read(&mut self, index: ComponentId) {
self.add_read(index);
}
#[deprecated(
since = "0.19.0",
note = "Call `FilteredAccessSet::add_resource_write`. If this is called in a `WorldQuery` impl, then you will need to implement `init_nested_access` to modify the `FilteredAccessSet`."
)]
pub fn add_resource_write(&mut self, index: ComponentId) {
self.add_write(index);
}
#[deprecated(since = "0.19.0", note = "use Access::remove_read")]
pub fn remove_component_read(&mut self, index: ComponentId) {
self.remove_read(index);
}
pub fn remove_read(&mut self, index: ComponentId) {
self.remove_write(index);
if self.read_and_writes_inverted {
self.read_and_writes.insert(index);
} else {
self.read_and_writes.remove(index);
}
}
#[deprecated(since = "0.19.0", note = "use Access::remove_write")]
pub fn remove_component_write(&mut self, index: ComponentId) {
self.remove_write(index);
}
pub fn remove_write(&mut self, index: ComponentId) {
if self.writes_inverted {
self.writes.insert(index);
} else {
self.writes.remove(index);
}
}
pub fn add_archetypal(&mut self, index: ComponentId) {
self.archetypal.insert(index);
}
#[deprecated(since = "0.19.0", note = "use Access::has_read")]
pub fn has_component_read(&self, index: ComponentId) -> bool {
self.has_read(index)
}
pub fn has_read(&self, index: ComponentId) -> bool {
self.read_and_writes_inverted ^ self.read_and_writes.contains(index)
}
#[deprecated(since = "0.19.0", note = "use Access::has_any_read")]
pub fn has_any_component_read(&self) -> bool {
self.has_any_read()
}
pub fn has_any_read(&self) -> bool {
self.read_and_writes_inverted || !self.read_and_writes.is_clear()
}
#[deprecated(since = "0.19.0", note = "use Access::has_write")]
pub fn has_component_write(&self, index: ComponentId) -> bool {
self.has_write(index)
}
pub fn has_write(&self, index: ComponentId) -> bool {
self.writes_inverted ^ self.writes.contains(index)
}
#[deprecated(since = "0.19.0", note = "use Access::has_any_write")]
pub fn has_any_component_write(&self) -> bool {
self.has_any_write()
}
pub fn has_any_write(&self) -> bool {
self.writes_inverted || !self.writes.is_clear()
}
#[deprecated(since = "0.19.0", note = "use Access::has_read")]
pub fn has_resource_read(&self, index: ComponentId) -> bool {
self.has_read(index)
}
#[deprecated(since = "0.19.0", note = "use Access::has_any_read")]
pub fn has_any_resource_read(&self) -> bool {
self.has_any_read()
}
#[deprecated(since = "0.19.0", note = "use Access::has_write")]
pub fn has_resource_write(&self, index: ComponentId) -> bool {
self.has_write(index)
}
#[deprecated(since = "0.19.0", note = "use Access::has_any_write")]
pub fn has_any_resource_write(&self) -> bool {
self.has_any_write()
}
pub fn has_archetypal(&self, index: ComponentId) -> bool {
self.archetypal.contains(index)
}
#[deprecated(since = "0.19.0", note = "use Access::read_all")]
pub fn read_all_components(&mut self) {
self.read_all();
}
#[inline]
pub fn read_all(&mut self) {
self.read_and_writes_inverted = true;
self.read_and_writes.clear();
}
#[deprecated(since = "0.19.0", note = "use Access::write_all")]
pub fn write_all_components(&mut self) {
self.write_all();
}
#[inline]
pub fn write_all(&mut self) {
self.read_all();
self.writes_inverted = true;
self.writes.clear();
}
#[deprecated(since = "0.19.0", note = "use Access::has_read_all")]
pub fn has_read_all_components(&self) -> bool {
self.has_read_all()
}
#[inline]
pub fn has_read_all(&self) -> bool {
self.read_and_writes_inverted && self.read_and_writes.is_clear()
}
#[deprecated(since = "0.19.0", note = "use Access::has_write_all")]
pub fn has_write_all_components(&self) -> bool {
self.has_write_all()
}
#[inline]
pub fn has_write_all(&self) -> bool {
self.writes_inverted && self.writes.is_clear()
}
pub fn clear_writes(&mut self) {
self.writes_inverted = false;
self.writes.clear();
}
pub fn clear(&mut self) {
self.read_and_writes_inverted = false;
self.writes_inverted = false;
self.read_and_writes.clear();
self.writes.clear();
}
pub fn extend(&mut self, other: &Access) {
invertible_union_with(
&mut self.read_and_writes,
&mut self.read_and_writes_inverted,
&other.read_and_writes,
other.read_and_writes_inverted,
);
invertible_union_with(
&mut self.writes,
&mut self.writes_inverted,
&other.writes,
other.writes_inverted,
);
self.archetypal.union_with(&other.archetypal);
}
pub fn remove_conflicting_access(&mut self, other: &Access) {
invertible_difference_with(
&mut self.read_and_writes,
&mut self.read_and_writes_inverted,
&other.writes,
other.writes_inverted,
);
invertible_difference_with(
&mut self.writes,
&mut self.writes_inverted,
&other.read_and_writes,
other.read_and_writes_inverted,
);
}
#[deprecated(since = "0.19.0", note = "use Access::is_compatible")]
pub fn is_components_compatible(&self, other: &Access) -> bool {
self.is_compatible(other)
}
pub fn is_compatible(&self, other: &Access) -> bool {
for (
lhs_writes,
rhs_reads_and_writes,
lhs_writes_inverted,
rhs_reads_and_writes_inverted,
) in [
(
&self.writes,
&other.read_and_writes,
self.writes_inverted,
other.read_and_writes_inverted,
),
(
&other.writes,
&self.read_and_writes,
other.writes_inverted,
self.read_and_writes_inverted,
),
] {
match (lhs_writes_inverted, rhs_reads_and_writes_inverted) {
(true, true) => return false,
(false, true) => {
if !lhs_writes.is_subset(rhs_reads_and_writes) {
return false;
}
}
(true, false) => {
if !rhs_reads_and_writes.is_subset(lhs_writes) {
return false;
}
}
(false, false) => {
if !lhs_writes.is_disjoint(rhs_reads_and_writes) {
return false;
}
}
}
}
true
}
#[deprecated(since = "0.19.0", note = "use Access::is_subset")]
pub fn is_subset_components(&self, other: &Access) -> bool {
self.is_subset(other)
}
pub fn is_subset(&self, other: &Access) -> bool {
for (
our_components,
their_components,
our_components_inverted,
their_components_inverted,
) in [
(
&self.read_and_writes,
&other.read_and_writes,
self.read_and_writes_inverted,
other.read_and_writes_inverted,
),
(
&self.writes,
&other.writes,
self.writes_inverted,
other.writes_inverted,
),
] {
match (our_components_inverted, their_components_inverted) {
(true, true) => {
if !their_components.is_subset(our_components) {
return false;
}
}
(true, false) => {
return false;
}
(false, true) => {
if !our_components.is_disjoint(their_components) {
return false;
}
}
(false, false) => {
if !our_components.is_subset(their_components) {
return false;
}
}
}
}
true
}
#[inline]
pub fn get_conflicts(&self, other: &Access) -> AccessConflicts {
let mut conflicts = ComponentIdSet::new();
for (
lhs_writes,
rhs_reads_and_writes,
lhs_writes_inverted,
rhs_reads_and_writes_inverted,
) in [
(
&self.writes,
&other.read_and_writes,
self.writes_inverted,
other.read_and_writes_inverted,
),
(
&other.writes,
&self.read_and_writes,
other.writes_inverted,
self.read_and_writes_inverted,
),
] {
let temp_conflicts: ComponentIdSet =
match (lhs_writes_inverted, rhs_reads_and_writes_inverted) {
(true, true) => return AccessConflicts::All,
(false, true) => lhs_writes.difference(rhs_reads_and_writes).collect(),
(true, false) => rhs_reads_and_writes.difference(lhs_writes).collect(),
(false, false) => lhs_writes.intersection(rhs_reads_and_writes).collect(),
};
conflicts.union_with(&temp_conflicts);
}
AccessConflicts::Individual(conflicts)
}
pub fn archetypal(&self) -> &ComponentIdSet {
&self.archetypal
}
pub fn try_reads_and_writes(&self) -> Result<&ComponentIdSet, UnboundedAccessError> {
if self.read_and_writes_inverted {
return Err(UnboundedAccessError {
writes_inverted: self.writes_inverted,
read_and_writes_inverted: self.read_and_writes_inverted,
});
}
Ok(&self.read_and_writes)
}
pub fn try_writes(&self) -> Result<&ComponentIdSet, UnboundedAccessError> {
if self.writes_inverted {
return Err(UnboundedAccessError {
writes_inverted: self.writes_inverted,
read_and_writes_inverted: self.read_and_writes_inverted,
});
}
Ok(&self.writes)
}
#[deprecated(since = "0.19.0", note = "use Access::try_iter_access")]
pub fn try_iter_component_access(
&self,
) -> Result<impl Iterator<Item = ComponentAccessKind> + '_, UnboundedAccessError> {
self.try_iter_access()
}
pub fn try_iter_access(
&self,
) -> Result<impl Iterator<Item = ComponentAccessKind> + '_, UnboundedAccessError> {
let reads_and_writes = self.try_reads_and_writes()?.iter().map(|index| {
if self.writes.contains(index) {
ComponentAccessKind::Exclusive(index)
} else {
ComponentAccessKind::Shared(index)
}
});
let archetypal = self
.archetypal
.difference(&self.read_and_writes)
.map(ComponentAccessKind::Archetypal);
Ok(reads_and_writes.chain(archetypal))
}
}
fn invertible_union_with(
self_set: &mut ComponentIdSet,
self_inverted: &mut bool,
other_set: &ComponentIdSet,
other_inverted: bool,
) {
match (*self_inverted, other_inverted) {
(true, true) => self_set.intersect_with(other_set),
(true, false) => self_set.difference_with(other_set),
(false, true) => {
*self_inverted = true;
self_set.difference_from(other_set);
}
(false, false) => self_set.union_with(other_set),
}
}
fn invertible_difference_with(
self_set: &mut ComponentIdSet,
self_inverted: &mut bool,
other_set: &ComponentIdSet,
other_inverted: bool,
) {
*self_inverted = !*self_inverted;
invertible_union_with(self_set, self_inverted, other_set, other_inverted);
*self_inverted = !*self_inverted;
}
#[derive(Clone, Copy, PartialEq, Eq, Debug, Error)]
#[error("Access is unbounded")]
pub struct UnboundedAccessError {
pub writes_inverted: bool,
pub read_and_writes_inverted: bool,
}
#[derive(PartialEq, Eq, Hash, Debug, Clone, Copy)]
pub enum ComponentAccessKind {
Archetypal(ComponentId),
Shared(ComponentId),
Exclusive(ComponentId),
}
impl ComponentAccessKind {
pub fn index(&self) -> &ComponentId {
let (Self::Archetypal(value) | Self::Shared(value) | Self::Exclusive(value)) = self;
value
}
}
#[derive(Debug, Eq, PartialEq)]
pub struct FilteredAccess {
pub(crate) access: Access,
pub(crate) required: ComponentIdSet,
pub(crate) filter_sets: Vec<AccessFilters>,
}
impl Clone for FilteredAccess {
fn clone(&self) -> Self {
Self {
access: self.access.clone(),
required: self.required.clone(),
filter_sets: self.filter_sets.clone(),
}
}
fn clone_from(&mut self, source: &Self) {
self.access.clone_from(&source.access);
self.required.clone_from(&source.required);
self.filter_sets.clone_from(&source.filter_sets);
}
}
impl Default for FilteredAccess {
fn default() -> Self {
Self::matches_everything()
}
}
impl From<FilteredAccess> for FilteredAccessSet {
fn from(filtered_access: FilteredAccess) -> Self {
let mut base = FilteredAccessSet::default();
base.add(filtered_access);
base
}
}
#[derive(Debug, PartialEq, From)]
pub enum AccessConflicts {
All,
Individual(ComponentIdSet),
}
impl AccessConflicts {
fn add(&mut self, other: &Self) {
match (self, other) {
(s, AccessConflicts::All) => {
*s = AccessConflicts::All;
}
(AccessConflicts::Individual(this), AccessConflicts::Individual(other)) => {
this.extend(other);
}
_ => {}
}
}
pub fn is_empty(&self) -> bool {
match self {
Self::All => false,
Self::Individual(set) => set.is_clear(),
}
}
pub(crate) fn format_conflict_list(&self, world: UnsafeWorldCell) -> String {
match self {
AccessConflicts::All => String::new(),
AccessConflicts::Individual(indices) => indices
.iter()
.map(|index| {
format!(
"{}",
world.components().get_name(index).unwrap().shortname()
)
})
.collect::<Vec<_>>()
.join(", "),
}
}
pub(crate) fn empty() -> Self {
Self::Individual(ComponentIdSet::new())
}
}
impl From<Vec<ComponentId>> for AccessConflicts {
fn from(value: Vec<ComponentId>) -> Self {
Self::Individual(value.into_iter().collect())
}
}
impl FilteredAccess {
pub fn matches_everything() -> Self {
Self {
access: Access::default(),
required: ComponentIdSet::default(),
filter_sets: vec![AccessFilters::default()],
}
}
pub fn matches_nothing() -> Self {
Self {
access: Access::default(),
required: ComponentIdSet::default(),
filter_sets: Vec::new(),
}
}
#[inline]
pub fn access(&self) -> &Access {
&self.access
}
#[inline]
pub fn access_mut(&mut self) -> &mut Access {
&mut self.access
}
#[deprecated(since = "0.19.0", note = "use FilteredAccess::add_read")]
pub fn add_component_read(&mut self, index: ComponentId) {
self.add_read(index);
}
pub fn add_read(&mut self, index: ComponentId) {
self.access.add_read(index);
self.add_required(index);
self.and_with(index);
}
#[deprecated(since = "0.19.0", note = "use FilteredAccess::add_write")]
pub fn add_component_write(&mut self, index: ComponentId) {
self.add_write(index);
}
pub fn add_write(&mut self, index: ComponentId) {
self.access.add_write(index);
self.add_required(index);
self.and_with(index);
}
fn add_required(&mut self, index: ComponentId) {
self.required.insert(index);
}
pub fn and_with(&mut self, index: ComponentId) {
for filter in &mut self.filter_sets {
filter.with.insert(index);
}
}
pub fn and_without(&mut self, index: ComponentId) {
for filter in &mut self.filter_sets {
filter.without.insert(index);
}
}
pub fn append_or(&mut self, other: &FilteredAccess) {
self.filter_sets.append(&mut other.filter_sets.clone());
}
pub fn extend_access(&mut self, other: &FilteredAccess) {
self.access.extend(&other.access);
}
pub fn is_compatible(&self, other: &FilteredAccess) -> bool {
if self.access.is_compatible(&other.access) {
return true;
}
self.filter_sets.iter().all(|filter| {
other
.filter_sets
.iter()
.all(|other_filter| filter.is_ruled_out_by(other_filter))
})
}
pub fn get_conflicts(&self, other: &FilteredAccess) -> AccessConflicts {
if !self.is_compatible(other) {
return self.access.get_conflicts(&other.access);
}
AccessConflicts::empty()
}
pub fn extend(&mut self, other: &FilteredAccess) {
self.access.extend(&other.access);
self.required.union_with(&other.required);
if other.filter_sets.len() == 1 {
for filter in &mut self.filter_sets {
filter.with.union_with(&other.filter_sets[0].with);
filter.without.union_with(&other.filter_sets[0].without);
}
return;
}
let mut new_filters = Vec::with_capacity(self.filter_sets.len() * other.filter_sets.len());
for filter in &self.filter_sets {
for other_filter in &other.filter_sets {
let mut new_filter = filter.clone();
new_filter.with.union_with(&other_filter.with);
new_filter.without.union_with(&other_filter.without);
new_filters.push(new_filter);
}
}
self.filter_sets = new_filters;
}
pub fn read_all(&mut self) {
self.access.read_all();
}
pub fn write_all(&mut self) {
self.access.write_all();
}
#[deprecated(since = "0.19.0", note = "use FilteredAccess::read_all")]
pub fn read_all_components(&mut self) {
self.read_all();
}
#[deprecated(since = "0.19.0", note = "use FilteredAccess::write_all")]
pub fn write_all_components(&mut self) {
self.write_all();
}
pub fn is_subset(&self, other: &FilteredAccess) -> bool {
self.required.is_subset(&other.required) && self.access().is_subset(other.access())
}
pub fn required(&self) -> &ComponentIdSet {
&self.required
}
pub fn filter_sets(&self) -> &[AccessFilters] {
&self.filter_sets
}
pub fn with_filters(&self) -> impl Iterator<Item = ComponentId> + '_ {
self.filter_sets.iter().flat_map(|f| f.with.iter())
}
pub fn without_filters(&self) -> impl Iterator<Item = ComponentId> + '_ {
self.filter_sets.iter().flat_map(|f| f.without.iter())
}
pub fn contains(&self, index: ComponentId) -> bool {
self.access().has_archetypal(index)
|| self
.filter_sets
.iter()
.any(|f| f.with.contains(index) || f.without.contains(index))
}
}
#[derive(Eq, PartialEq, Default, Debug)]
pub struct AccessFilters {
pub(crate) with: ComponentIdSet,
pub(crate) without: ComponentIdSet,
}
impl Clone for AccessFilters {
fn clone(&self) -> Self {
Self {
with: self.with.clone(),
without: self.without.clone(),
}
}
fn clone_from(&mut self, source: &Self) {
self.with.clone_from(&source.with);
self.without.clone_from(&source.without);
}
}
impl AccessFilters {
pub fn with(&self) -> &ComponentIdSet {
&self.with
}
pub fn without(&self) -> &ComponentIdSet {
&self.without
}
fn is_ruled_out_by(&self, other: &Self) -> bool {
!self.with.is_disjoint(&other.without) || !self.without.is_disjoint(&other.with)
}
}
#[derive(Debug, PartialEq, Eq, Default)]
pub struct FilteredAccessSet {
combined_access: Access,
filtered_accesses: Vec<FilteredAccess>,
}
impl Clone for FilteredAccessSet {
fn clone(&self) -> Self {
Self {
combined_access: self.combined_access.clone(),
filtered_accesses: self.filtered_accesses.clone(),
}
}
fn clone_from(&mut self, source: &Self) {
self.combined_access.clone_from(&source.combined_access);
self.filtered_accesses.clone_from(&source.filtered_accesses);
}
}
impl FilteredAccessSet {
pub const fn new() -> Self {
Self {
combined_access: Access::new(),
filtered_accesses: Vec::new(),
}
}
#[inline]
pub fn combined_access(&self) -> &Access {
&self.combined_access
}
#[inline]
pub fn filtered_accesses(&self) -> &[FilteredAccess] {
&self.filtered_accesses
}
pub fn is_compatible(&self, other: &FilteredAccessSet) -> bool {
if self.combined_access.is_compatible(other.combined_access()) {
return true;
}
for filtered in &self.filtered_accesses {
for other_filtered in &other.filtered_accesses {
if !filtered.is_compatible(other_filtered) {
return false;
}
}
}
true
}
pub fn get_conflicts(&self, other: &FilteredAccessSet) -> AccessConflicts {
let mut conflicts = AccessConflicts::empty();
if !self.combined_access.is_compatible(other.combined_access()) {
for filtered in &self.filtered_accesses {
for other_filtered in &other.filtered_accesses {
conflicts.add(&filtered.get_conflicts(other_filtered));
}
}
}
conflicts
}
pub fn get_conflicts_single(&self, filtered_access: &FilteredAccess) -> AccessConflicts {
let mut conflicts = AccessConflicts::empty();
if !self.combined_access.is_compatible(filtered_access.access()) {
for filtered in &self.filtered_accesses {
conflicts.add(&filtered.get_conflicts(filtered_access));
}
}
conflicts
}
pub fn add(&mut self, filtered_access: FilteredAccess) {
self.combined_access.extend(&filtered_access.access);
self.filtered_accesses.push(filtered_access);
}
#[deprecated(since = "0.19.0", note = "FilteredAccessSet::add_resource_read")]
pub fn add_unfiltered_resource_read(&mut self, index: ComponentId) {
self.add_resource_read(index);
}
pub fn add_resource_read(&mut self, index: ComponentId) {
let mut filter = FilteredAccess::default();
filter.add_read(index);
filter.and_with(IS_RESOURCE);
self.add(filter);
}
pub(crate) fn add_unfiltered_component_read(&mut self, index: ComponentId) {
let mut filter = FilteredAccess::default();
filter.add_read(index);
self.add(filter);
}
pub fn add_unfiltered_read_all_components(&mut self) {
let mut filter = FilteredAccess::default();
filter.access.read_all();
self.add(filter);
}
#[deprecated(since = "0.19.0", note = "FilteredAccessSet::add_resource_write")]
pub fn add_unfiltered_resource_write(&mut self, index: ComponentId) {
self.add_resource_write(index);
}
pub fn add_resource_write(&mut self, index: ComponentId) {
let mut filter = FilteredAccess::default();
filter.add_write(index);
filter.and_with(IS_RESOURCE);
self.add(filter);
}
pub(crate) fn add_unfiltered_component_write(&mut self, index: ComponentId) {
let mut filter = FilteredAccess::default();
filter.add_write(index);
self.add(filter);
}
pub fn add_unfiltered_write_all_components(&mut self) {
let mut filter = FilteredAccess::default();
filter.write_all();
self.add(filter);
}
pub fn extend(&mut self, filtered_access_set: FilteredAccessSet) {
self.combined_access
.extend(&filtered_access_set.combined_access);
self.filtered_accesses
.extend(filtered_access_set.filtered_accesses);
}
pub fn read_all(&mut self) {
let mut filter = FilteredAccess::matches_everything();
filter.read_all();
self.add(filter);
}
pub fn write_all(&mut self) {
let mut filter = FilteredAccess::matches_everything();
filter.write_all();
self.add(filter);
}
pub fn clear(&mut self) {
self.combined_access.clear();
self.filtered_accesses.clear();
}
}
#[derive(Default, Eq, PartialEq, Hash)]
#[repr(transparent)]
pub struct ComponentIdSet(FixedBitSet);
impl ComponentIdSet {
#[inline]
pub const fn new() -> Self {
Self(FixedBitSet::new())
}
#[cfg(test)]
pub(crate) fn from_bits(bits: FixedBitSet) -> Self {
Self(bits)
}
#[inline]
pub fn insert(&mut self, index: ComponentId) {
self.0.grow_and_insert(index.index());
}
#[inline]
pub fn remove(&mut self, index: ComponentId) {
if index.index() < self.0.len() {
self.0.remove(index.index());
}
}
#[inline]
pub fn clear(&mut self) {
self.0.clear();
}
#[inline]
pub fn contains(&self, index: ComponentId) -> bool {
self.0.contains(index.index())
}
#[inline]
pub fn is_disjoint(&self, other: &ComponentIdSet) -> bool {
self.0.is_disjoint(&other.0)
}
#[inline]
pub fn is_subset(&self, other: &ComponentIdSet) -> bool {
self.0.is_subset(&other.0)
}
#[inline]
pub fn is_clear(&self) -> bool {
self.0.is_clear()
}
#[inline]
pub fn iter(&self) -> ComponentIdIter<Ones<'_>> {
ComponentIdIter(self.0.ones())
}
#[inline]
pub fn union<'a>(&'a self, other: &'a ComponentIdSet) -> ComponentIdIter<Union<'a>> {
ComponentIdIter(self.0.union(&other.0))
}
#[inline]
pub fn intersection<'a>(
&'a self,
other: &'a ComponentIdSet,
) -> ComponentIdIter<Intersection<'a>> {
ComponentIdIter(self.0.intersection(&other.0))
}
#[inline]
pub fn difference<'a>(&'a self, other: &'a ComponentIdSet) -> ComponentIdIter<Difference<'a>> {
ComponentIdIter(self.0.difference(&other.0))
}
#[inline]
pub fn union_with(&mut self, other: &ComponentIdSet) {
self.0.union_with(&other.0);
}
#[inline]
pub fn intersect_with(&mut self, other: &ComponentIdSet) {
self.0.intersect_with(&other.0);
}
#[inline]
pub fn difference_with(&mut self, other: &ComponentIdSet) {
self.0.difference_with(&other.0);
}
#[inline]
pub fn difference_from(&mut self, other: &ComponentIdSet) {
self.0.grow(other.0.len());
self.0.toggle_range(..);
self.0.intersect_with(&other.0);
}
}
impl Debug for ComponentIdSet {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_list().entries(self.0.ones()).finish()
}
}
impl Clone for ComponentIdSet {
#[inline]
fn clone(&self) -> Self {
Self(self.0.clone())
}
#[inline]
fn clone_from(&mut self, source: &Self) {
self.0.clone_from(&source.0);
}
}
impl IntoIterator for ComponentIdSet {
type Item = ComponentId;
type IntoIter = ComponentIdIter<IntoOnes>;
#[inline]
fn into_iter(self) -> Self::IntoIter {
ComponentIdIter(self.0.into_ones())
}
}
impl<'a> IntoIterator for &'a ComponentIdSet {
type Item = ComponentId;
type IntoIter = ComponentIdIter<Ones<'a>>;
#[inline]
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
impl FromIterator<ComponentId> for ComponentIdSet {
#[inline]
fn from_iter<T: IntoIterator<Item = ComponentId>>(iter: T) -> Self {
Self(FixedBitSet::from_iter(
iter.into_iter().map(ComponentId::index),
))
}
}
impl Extend<ComponentId> for ComponentIdSet {
#[inline]
fn extend<T: IntoIterator<Item = ComponentId>>(&mut self, iter: T) {
self.0.extend(iter.into_iter().map(ComponentId::index));
}
}
#[repr(transparent)]
pub struct ComponentIdIter<I>(I);
impl<I: Iterator<Item = usize>> Iterator for ComponentIdIter<I> {
type Item = ComponentId;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
self.0.next().map(ComponentId::new)
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
self.0.size_hint()
}
}
impl<I: DoubleEndedIterator<Item = usize>> DoubleEndedIterator for ComponentIdIter<I> {
#[inline]
fn next_back(&mut self) -> Option<Self::Item> {
self.0.next_back().map(ComponentId::new)
}
}
impl<I: FusedIterator<Item = usize>> FusedIterator for ComponentIdIter<I> {}
#[cfg(test)]
mod tests {
use super::{invertible_difference_with, invertible_union_with};
use crate::{
component::ComponentId,
query::{
access::AccessFilters, Access, AccessConflicts, ComponentAccessKind, ComponentIdSet,
FilteredAccess, FilteredAccessSet, UnboundedAccessError,
},
};
use alloc::{vec, vec::Vec};
use fixedbitset::FixedBitSet;
fn create_sample_access() -> Access {
let mut access = Access::default();
access.add_read(ComponentId::new(1));
access.add_read(ComponentId::new(2));
access.add_write(ComponentId::new(3));
access.add_archetypal(ComponentId::new(5));
access.read_all();
access
}
fn create_sample_filtered_access() -> FilteredAccess {
let mut filtered_access = FilteredAccess::default();
filtered_access.add_write(ComponentId::new(1));
filtered_access.add_read(ComponentId::new(2));
filtered_access.add_required(ComponentId::new(3));
filtered_access.and_with(ComponentId::new(4));
filtered_access
}
fn create_sample_access_filters() -> AccessFilters {
let mut access_filters = AccessFilters::default();
access_filters.with.insert(ComponentId::new(3));
access_filters.without.insert(ComponentId::new(5));
access_filters
}
fn create_sample_filtered_access_set() -> FilteredAccessSet {
let mut filtered_access_set = FilteredAccessSet::default();
filtered_access_set.add_unfiltered_component_read(ComponentId::new(2));
filtered_access_set.add_unfiltered_component_write(ComponentId::new(4));
filtered_access_set.read_all();
filtered_access_set
}
#[test]
fn test_access_clone() {
let original = create_sample_access();
let cloned = original.clone();
assert_eq!(original, cloned);
}
#[test]
fn test_access_clone_from() {
let original = create_sample_access();
let mut cloned = Access::default();
cloned.add_write(ComponentId::new(7));
cloned.add_read(ComponentId::new(4));
cloned.add_archetypal(ComponentId::new(8));
cloned.write_all();
cloned.clone_from(&original);
assert_eq!(original, cloned);
}
#[test]
fn test_filtered_access_clone() {
let original = create_sample_filtered_access();
let cloned = original.clone();
assert_eq!(original, cloned);
}
#[test]
fn test_filtered_access_clone_from() {
let original = create_sample_filtered_access();
let mut cloned = FilteredAccess::default();
cloned.add_write(ComponentId::new(7));
cloned.add_read(ComponentId::new(4));
cloned.append_or(&FilteredAccess::default());
cloned.clone_from(&original);
assert_eq!(original, cloned);
}
#[test]
fn test_access_filters_clone() {
let original = create_sample_access_filters();
let cloned = original.clone();
assert_eq!(original, cloned);
}
#[test]
fn test_access_filters_clone_from() {
let original = create_sample_access_filters();
let mut cloned = AccessFilters::default();
cloned.with.insert(ComponentId::new(1));
cloned.without.insert(ComponentId::new(2));
cloned.clone_from(&original);
assert_eq!(original, cloned);
}
#[test]
fn test_filtered_access_set_clone() {
let original = create_sample_filtered_access_set();
let cloned = original.clone();
assert_eq!(original, cloned);
}
#[test]
fn test_filtered_access_set_from() {
let original = create_sample_filtered_access_set();
let mut cloned = FilteredAccessSet::default();
cloned.add_unfiltered_component_read(ComponentId::new(7));
cloned.add_unfiltered_component_write(ComponentId::new(9));
cloned.write_all();
cloned.clone_from(&original);
assert_eq!(original, cloned);
}
#[test]
fn read_all_access_conflicts() {
let mut access_a = Access::default();
access_a.add_write(ComponentId::new(0));
let mut access_b = Access::default();
access_b.read_all();
assert!(!access_b.is_compatible(&access_a));
let mut access_a = Access::default();
access_a.read_all();
let mut access_b = Access::default();
access_b.read_all();
assert!(access_b.is_compatible(&access_a));
}
#[test]
fn access_get_conflicts() {
let mut access_a = Access::default();
access_a.add_read(ComponentId::new(0));
access_a.add_read(ComponentId::new(1));
let mut access_b = Access::default();
access_b.add_read(ComponentId::new(0));
access_b.add_write(ComponentId::new(1));
assert_eq!(
access_a.get_conflicts(&access_b),
vec![ComponentId::new(1)].into()
);
let mut access_c = Access::default();
access_c.add_write(ComponentId::new(0));
access_c.add_write(ComponentId::new(1));
assert_eq!(
access_a.get_conflicts(&access_c),
vec![ComponentId::new(0), ComponentId::new(1)].into()
);
assert_eq!(
access_b.get_conflicts(&access_c),
vec![ComponentId::new(0), ComponentId::new(1)].into()
);
let mut access_d = Access::default();
access_d.add_read(ComponentId::new(0));
assert_eq!(access_d.get_conflicts(&access_a), AccessConflicts::empty());
assert_eq!(access_d.get_conflicts(&access_b), AccessConflicts::empty());
assert_eq!(
access_d.get_conflicts(&access_c),
vec![ComponentId::new(0)].into()
);
}
#[test]
fn filtered_combined_access() {
let mut access_a = FilteredAccessSet::default();
access_a.add_unfiltered_component_read(ComponentId::new(1));
let mut filter_b = FilteredAccess::default();
filter_b.add_write(ComponentId::new(1));
let conflicts = access_a.get_conflicts_single(&filter_b);
assert_eq!(
&conflicts,
&AccessConflicts::from(vec![ComponentId::new(1)]),
"access_a: {access_a:?}, filter_b: {filter_b:?}"
);
}
#[test]
fn filtered_access_extend() {
let mut access_a = FilteredAccess::default();
access_a.add_read(ComponentId::new(0));
access_a.add_read(ComponentId::new(1));
access_a.and_with(ComponentId::new(2));
let mut access_b = FilteredAccess::default();
access_b.add_read(ComponentId::new(0));
access_b.add_write(ComponentId::new(3));
access_b.and_without(ComponentId::new(4));
access_a.extend(&access_b);
let mut expected = FilteredAccess::default();
expected.add_read(ComponentId::new(0));
expected.add_read(ComponentId::new(1));
expected.and_with(ComponentId::new(2));
expected.add_write(ComponentId::new(3));
expected.and_without(ComponentId::new(4));
assert!(access_a.eq(&expected));
}
#[test]
fn filtered_access_extend_or() {
let mut access_a = FilteredAccess::default();
access_a.add_write(ComponentId::new(0));
access_a.add_write(ComponentId::new(1));
let mut access_b = FilteredAccess::default();
access_b.and_with(ComponentId::new(2));
let mut access_c = FilteredAccess::default();
access_c.and_with(ComponentId::new(3));
access_c.and_without(ComponentId::new(4));
access_b.append_or(&access_c);
access_a.extend(&access_b);
let mut expected = FilteredAccess::default();
expected.add_write(ComponentId::new(0));
expected.add_write(ComponentId::new(1));
expected.filter_sets = vec![
AccessFilters {
with: ComponentIdSet::from_bits(FixedBitSet::with_capacity_and_blocks(3, [0b111])),
without: ComponentIdSet::default(),
},
AccessFilters {
with: ComponentIdSet::from_bits(FixedBitSet::with_capacity_and_blocks(4, [0b1011])),
without: ComponentIdSet::from_bits(FixedBitSet::with_capacity_and_blocks(
5,
[0b10000],
)),
},
];
assert_eq!(access_a, expected);
}
#[test]
fn try_iter_component_access_simple() {
let mut access = Access::default();
access.add_read(ComponentId::new(1));
access.add_read(ComponentId::new(2));
access.add_write(ComponentId::new(3));
access.add_archetypal(ComponentId::new(5));
let result = access.try_iter_access().map(Iterator::collect::<Vec<_>>);
assert_eq!(
result,
Ok(vec![
ComponentAccessKind::Shared(ComponentId::new(1)),
ComponentAccessKind::Shared(ComponentId::new(2)),
ComponentAccessKind::Exclusive(ComponentId::new(3)),
ComponentAccessKind::Archetypal(ComponentId::new(5)),
]),
);
}
#[test]
fn try_iter_component_access_unbounded_write_all() {
let mut access = Access::default();
access.add_read(ComponentId::new(1));
access.add_read(ComponentId::new(2));
access.write_all();
let result = access.try_iter_access().map(Iterator::collect::<Vec<_>>);
assert_eq!(
result,
Err(UnboundedAccessError {
writes_inverted: true,
read_and_writes_inverted: true
}),
);
}
#[test]
fn try_iter_component_access_unbounded_read_all() {
let mut access = Access::default();
access.add_read(ComponentId::new(1));
access.add_read(ComponentId::new(2));
access.read_all();
let result = access.try_iter_access().map(Iterator::collect::<Vec<_>>);
assert_eq!(
result,
Err(UnboundedAccessError {
writes_inverted: false,
read_and_writes_inverted: true
}),
);
}
fn bit_set(bits: usize, iter: impl IntoIterator<Item = usize>) -> ComponentIdSet {
let mut result = FixedBitSet::with_capacity(bits);
result.extend(iter);
ComponentIdSet::from_bits(result)
}
#[test]
fn invertible_union_with_tests() {
let invertible_union = |mut self_inverted: bool, other_inverted: bool| {
let mut self_set = bit_set(4, [0, 1]);
let other_set = bit_set(4, [0, 2]);
invertible_union_with(
&mut self_set,
&mut self_inverted,
&other_set,
other_inverted,
);
(self_set, self_inverted)
};
let (s, i) = invertible_union(false, false);
assert_eq!((s, i), (bit_set(4, [0, 1, 2]), false));
let (s, i) = invertible_union(false, true);
assert_eq!((s, i), (bit_set(4, [2]), true));
let (s, i) = invertible_union(true, false);
assert_eq!((s, i), (bit_set(4, [1]), true));
let (s, i) = invertible_union(true, true);
assert_eq!((s, i), (bit_set(4, [0]), true));
}
#[test]
fn invertible_union_with_different_lengths() {
let mut self_set = bit_set(1, [0]);
let mut self_inverted = false;
let other_set = bit_set(3, [0, 1]);
let other_inverted = true;
invertible_union_with(
&mut self_set,
&mut self_inverted,
&other_set,
other_inverted,
);
assert_eq!((self_set, self_inverted), (bit_set(3, [1]), true));
}
#[test]
fn invertible_difference_with_tests() {
let invertible_difference = |mut self_inverted: bool, other_inverted: bool| {
let mut self_set = bit_set(4, [0, 1]);
let other_set = bit_set(4, [0, 2]);
invertible_difference_with(
&mut self_set,
&mut self_inverted,
&other_set,
other_inverted,
);
(self_set, self_inverted)
};
let (s, i) = invertible_difference(false, false);
assert_eq!((s, i), (bit_set(4, [1]), false));
let (s, i) = invertible_difference(false, true);
assert_eq!((s, i), (bit_set(4, [0]), false));
let (s, i) = invertible_difference(true, false);
assert_eq!((s, i), (bit_set(4, [0, 1, 2]), true));
let (s, i) = invertible_difference(true, true);
assert_eq!((s, i), (bit_set(4, [2]), false));
}
#[test]
fn component_id_set_insert_remove_clear() {
let mut set = ComponentIdSet::new();
assert!(!set.contains(ComponentId::new(0)));
assert!(!set.contains(ComponentId::new(1)));
assert!(!set.contains(ComponentId::new(2)));
assert!(set.is_clear());
set.insert(ComponentId::new(2));
set.insert(ComponentId::new(1));
assert!(!set.contains(ComponentId::new(0)));
assert!(set.contains(ComponentId::new(1)));
assert!(set.contains(ComponentId::new(2)));
assert!(!set.is_clear());
set.remove(ComponentId::new(1));
assert!(!set.contains(ComponentId::new(0)));
assert!(!set.contains(ComponentId::new(1)));
assert!(set.contains(ComponentId::new(2)));
assert!(!set.is_clear());
set.insert(ComponentId::new(2));
set.insert(ComponentId::new(1));
assert!(!set.contains(ComponentId::new(0)));
assert!(set.contains(ComponentId::new(1)));
assert!(set.contains(ComponentId::new(2)));
assert!(!set.is_clear());
set.clear();
assert!(!set.contains(ComponentId::new(0)));
assert!(!set.contains(ComponentId::new(1)));
assert!(!set.contains(ComponentId::new(2)));
assert!(set.is_clear());
}
#[test]
fn component_id_set_remove_out_of_range() {
let mut set = ComponentIdSet::new();
set.remove(ComponentId::new(3));
set.insert(ComponentId::new(1));
set.remove(ComponentId::new(4));
assert!(set.iter().eq([1].map(ComponentId::new)));
}
#[test]
fn component_id_set_is_subset_is_disjoint() {
let set_1234 = ComponentIdSet::from_iter([1, 2, 3, 4].map(ComponentId::new));
let set_23 = ComponentIdSet::from_iter([2, 3].map(ComponentId::new));
let set_45 = ComponentIdSet::from_iter([4, 5].map(ComponentId::new));
assert!(set_23.is_subset(&set_1234));
assert!(!set_1234.is_subset(&set_23));
assert!(set_23.is_disjoint(&set_45));
assert!(set_45.is_disjoint(&set_23));
assert!(!set_1234.is_disjoint(&set_23));
assert!(!set_23.is_disjoint(&set_1234));
}
#[test]
fn component_id_set_union_intersection_difference() {
let set_13 = ComponentIdSet::from_iter([1, 3].map(ComponentId::new));
let set_23 = ComponentIdSet::from_iter([2, 3].map(ComponentId::new));
assert!(set_13.union(&set_23).eq([1, 3, 2].map(ComponentId::new)));
assert!(set_23.union(&set_13).eq([2, 3, 1].map(ComponentId::new)));
assert!(set_13.intersection(&set_23).eq([3].map(ComponentId::new)));
assert!(set_23.intersection(&set_13).eq([3].map(ComponentId::new)));
assert!(set_13.difference(&set_23).eq([1].map(ComponentId::new)));
assert!(set_23.difference(&set_13).eq([2].map(ComponentId::new)));
}
#[test]
fn component_id_set_union_intersection_difference_with() {
let set_13 = ComponentIdSet::from_iter([1, 3].map(ComponentId::new));
let set_23 = ComponentIdSet::from_iter([2, 3].map(ComponentId::new));
let mut s = set_13.clone();
s.union_with(&set_23);
assert!(s.iter().eq([1, 2, 3].map(ComponentId::new)));
let mut s = set_23.clone();
s.union_with(&set_13);
assert!(s.iter().eq([1, 2, 3].map(ComponentId::new)));
let mut s = set_13.clone();
s.intersect_with(&set_23);
assert!(s.iter().eq([3].map(ComponentId::new)));
let mut s = set_23.clone();
s.intersect_with(&set_13);
assert!(s.iter().eq([3].map(ComponentId::new)));
let mut s = set_13.clone();
s.difference_with(&set_23);
assert!(s.iter().eq([1].map(ComponentId::new)));
let mut s = set_23.clone();
s.difference_with(&set_13);
assert!(s.iter().eq([2].map(ComponentId::new)));
let mut s = set_13.clone();
s.difference_from(&set_23);
assert!(s.iter().eq([2].map(ComponentId::new)));
let mut s = set_23.clone();
s.difference_from(&set_13);
assert!(s.iter().eq([1].map(ComponentId::new)));
}
}