1use alloc::vec::Vec;
2use atomic_refcell::AtomicRef;
3use core::marker::PhantomData;
4
5use crate::{
6 archetype::{Cell, RefMut, Slot},
7 component::ComponentValue,
8 system::{Access, AccessKind},
9 Component, Entity, Fetch, FetchItem,
10};
11
12use super::{FetchAccessData, PreparedFetch, RandomFetch};
13
14pub struct MaybeMut<T>(pub(crate) Component<T>);
22
23impl<'q, T: ComponentValue> FetchItem<'q> for MaybeMut<T> {
24 type Item = MutGuard<'q, T>;
25}
26
27impl<'w, T: ComponentValue> Fetch<'w> for MaybeMut<T> {
28 const MUTABLE: bool = false;
29
30 type Prepared = PreparedMaybeMut<'w, T>;
31
32 fn prepare(&'w self, data: super::FetchPrepareData<'w>) -> Option<Self::Prepared> {
33 let cell = data.arch.cell(self.0.key())?;
34 Some(PreparedMaybeMut {
35 cell,
36 new_tick: data.new_tick,
37 entities: data.arch.entities(),
38 _marker: PhantomData,
39 })
40 }
41
42 fn filter_arch(&self, data: FetchAccessData) -> bool {
43 data.arch.has(self.0.key())
44 }
45
46 fn access(&self, data: FetchAccessData, dst: &mut Vec<Access>) {
47 if data.arch.has(self.0.key()) {
48 dst.extend_from_slice(&[Access {
49 kind: AccessKind::Archetype {
50 id: data.arch_id,
51 component: self.0.key(),
52 },
53 mutable: true,
54 }])
55 }
56 }
57
58 fn describe(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
59 f.write_str("mut ")?;
60 f.write_str(self.0.name())
61 }
62
63 fn searcher(&self, searcher: &mut crate::ArchetypeSearcher) {
64 searcher.add_required(self.0.key())
65 }
66
67 fn by_ref(&self) -> crate::filter::RefFetch<Self>
68 where
69 Self: Sized,
70 {
71 crate::filter::RefFetch(self)
72 }
73}
74
75pub struct PreparedMaybeMut<'w, T> {
76 cell: &'w Cell,
77 new_tick: u32,
78 entities: &'w [Entity],
79 _marker: PhantomData<T>,
80}
81
82pub struct Batch<'a> {
83 cell: &'a Cell,
84 new_tick: u32,
85 ids: &'a [Entity],
86 slot: Slot,
87}
88
89impl<'w, 'q, T: ComponentValue> PreparedFetch<'q> for PreparedMaybeMut<'w, T> {
90 type Item = MutGuard<'q, T>;
91 type Chunk = Batch<'q>;
92
93 const HAS_FILTER: bool = false;
94
95 unsafe fn create_chunk(&'q mut self, slice: crate::archetype::Slice) -> Self::Chunk {
96 Batch {
97 cell: self.cell,
98 new_tick: self.new_tick,
99 ids: self.entities,
100 slot: slice.start,
101 }
102 }
103
104 unsafe fn fetch_next(chunk: &mut Self::Chunk) -> Self::Item {
105 let slot = chunk.slot;
106 chunk.slot += 1;
107
108 MutGuard {
109 slot,
110 cell: chunk.cell,
111 new_tick: chunk.new_tick,
112 id: *chunk.ids.get_unchecked(slot),
113 _marker: PhantomData,
114 }
115 }
116}
117
118impl<'w, 'q, T: ComponentValue> RandomFetch<'q> for PreparedMaybeMut<'w, T> {
119 #[inline]
120 unsafe fn fetch_shared(&'q self, slot: usize) -> Self::Item {
121 MutGuard {
122 slot,
123 cell: self.cell,
124 new_tick: self.new_tick,
125 id: self.entities[slot],
126 _marker: PhantomData,
127 }
128 }
129
130 unsafe fn fetch_shared_chunk(chunk: &Self::Chunk, slot: Slot) -> Self::Item {
131 MutGuard {
132 slot,
133 cell: chunk.cell,
134 new_tick: chunk.new_tick,
135 id: chunk.ids[slot],
136 _marker: PhantomData,
137 }
138 }
139}
140
141pub struct MutGuard<'w, T> {
145 slot: Slot,
146 id: Entity,
147 cell: &'w Cell,
148 new_tick: u32,
149 _marker: PhantomData<T>,
150}
151
152impl<'w, T: ComponentValue> MutGuard<'w, T> {
153 pub fn read(&self) -> AtomicRef<T> {
155 unsafe { self.cell.get(self.slot).unwrap() }
157 }
158
159 pub fn write(&self) -> RefMut<T> {
163 self.cell
165 .get_mut(self.id, self.slot, self.new_tick)
166 .unwrap()
167 }
168}