1use core::{
2 any::{type_name, TypeId},
3 marker::PhantomData,
4 ptr::NonNull,
5};
6
7use crate::{
8 archetype::Archetype,
9 component::ComponentInfo,
10 query::SendQuery,
11 system::ActionBufferQueue,
12 view::{acquire, release, RuntimeBorrowState, StaticallyBorrowed, View, ViewCell, ViewValue},
13 world::World,
14 Access,
15};
16
17use super::{FnArg, FnArgState};
18
19pub trait QueryArg: SendQuery {
21 fn new() -> Self;
23
24 #[inline(always)]
26 fn before(&mut self, world: &World) {
27 let _ = world;
28 }
29
30 #[inline(always)]
32 fn after(&mut self, world: &World) {
33 let _ = world;
34 }
35}
36
37#[derive(Default)]
39pub struct ViewState<Q, F, B> {
40 query: Q,
41 filter: F,
42 marker: PhantomData<B>,
43}
44
45impl<'a, Q, F> FnArg for ViewValue<'a, Q, F, RuntimeBorrowState>
46where
47 Q: QueryArg,
48 F: QueryArg,
49{
50 type State = ViewState<Q, F, RuntimeBorrowState>;
51}
52
53unsafe impl<Q, F> FnArgState for ViewState<Q, F, RuntimeBorrowState>
54where
55 Q: QueryArg,
56 F: QueryArg,
57{
58 type Arg<'a> = ViewValue<'a, Q, F, RuntimeBorrowState>;
59
60 #[inline(always)]
61 fn new() -> Self {
62 ViewState {
63 query: Q::new(),
64 filter: F::new(),
65 marker: PhantomData,
66 }
67 }
68
69 #[inline(always)]
70 fn is_local(&self) -> bool {
71 false
72 }
73
74 #[inline(always)]
75 fn world_access(&self) -> Option<Access> {
76 Some(Access::Read)
77 }
78
79 #[inline(always)]
80 fn visit_archetype(&self, archetype: &Archetype) -> bool {
81 self.query.visit_archetype(archetype) && self.filter.visit_archetype(archetype)
82 }
83
84 #[inline(always)]
85 fn borrows_components_at_runtime(&self) -> bool {
86 true
87 }
88
89 #[inline(always)]
90 fn component_access(&self, comp: &ComponentInfo) -> Option<Access> {
91 let q = self
92 .query
93 .component_access(comp)
94 .unwrap_or(Some(Access::Write));
95 let f = self
96 .filter
97 .component_access(comp)
98 .unwrap_or(Some(Access::Write));
99
100 match (q, f) {
101 (None, one) | (one, None) => one,
102 (Some(Access::Read), Some(Access::Read)) => Some(Access::Read),
103 _ => {
104 Some(Access::Write)
106 }
107 }
108 }
109
110 #[inline(always)]
111 fn resource_type_access(&self, _ty: TypeId) -> Option<Access> {
112 None
113 }
114
115 #[inline(always)]
116 unsafe fn get_unchecked<'a>(
117 &'a mut self,
118 world: NonNull<World>,
119 _queue: &mut dyn ActionBufferQueue,
120 ) -> ViewCell<'a, Q, F> {
121 let world = unsafe { world.as_ref() };
123 self.query.before(world);
124 self.filter.before(world);
125 ViewValue::new_cell(world, self.query, self.filter)
126 }
127
128 #[inline(always)]
129 unsafe fn flush_unchecked(
130 &mut self,
131 world: NonNull<World>,
132 _queue: &mut dyn ActionBufferQueue,
133 ) {
134 let world = unsafe { world.as_ref() };
136 self.query.after(world);
137 self.filter.after(world);
138 }
139}
140
141impl<'a, Q, F> FnArg for ViewValue<'a, Q, F, StaticallyBorrowed>
142where
143 Q: QueryArg,
144 F: QueryArg,
145{
146 type State = ViewState<Q, F, StaticallyBorrowed>;
147}
148
149unsafe impl<Q, F> FnArgState for ViewState<Q, F, StaticallyBorrowed>
150where
151 Q: QueryArg,
152 F: QueryArg,
153{
154 type Arg<'a> = ViewValue<'a, Q, F, StaticallyBorrowed>;
155
156 #[inline(always)]
157 fn new() -> Self {
158 ViewState {
159 query: Q::new(),
160 filter: F::new(),
161 marker: PhantomData,
162 }
163 }
164
165 #[inline(always)]
166 fn is_local(&self) -> bool {
167 false
168 }
169
170 #[inline(always)]
171 fn world_access(&self) -> Option<Access> {
172 Some(Access::Read)
173 }
174
175 #[inline(always)]
176 fn visit_archetype(&self, archetype: &Archetype) -> bool {
177 self.query.visit_archetype(archetype) && self.filter.visit_archetype(archetype)
178 }
179
180 #[inline(always)]
181 fn borrows_components_at_runtime(&self) -> bool {
182 false
183 }
184
185 #[inline(always)]
186 fn component_access(&self, comp: &ComponentInfo) -> Option<Access> {
187 let Ok(q) = self.query.component_access(comp) else {
188 panic!("Mutable alias in query of `{}`", type_name::<Self>());
189 };
190 let Ok(f) = self.filter.component_access(comp) else {
191 panic!("Mutable alias in filter of `{}`", type_name::<Self>());
192 };
193
194 match (q, f) {
195 (None, one) | (one, None) => one,
196 (Some(Access::Read), Some(Access::Read)) => Some(Access::Read),
197 _ => {
198 panic!(
199 "Conflicting query and filter in `{}`.
200 A component is aliased mutably.",
201 core::any::type_name::<Self>()
202 );
203 }
204 }
205 }
206
207 #[inline(always)]
208 fn resource_type_access(&self, _ty: TypeId) -> Option<Access> {
209 None
210 }
211
212 #[inline(always)]
213 unsafe fn get_unchecked<'a>(
214 &'a mut self,
215 world: NonNull<World>,
216 _queue: &mut dyn ActionBufferQueue,
217 ) -> View<'a, Q, F> {
218 let world = unsafe { world.as_ref() };
220
221 #[cfg(debug_assertions)]
222 acquire(self.query, self.filter, world.archetypes());
223
224 self.query.before(world);
225 self.filter.before(world);
226
227 unsafe { ViewValue::new_static(world, self.query, self.filter) }
229 }
230
231 #[inline(always)]
232 unsafe fn flush_unchecked(
233 &mut self,
234 world: NonNull<World>,
235 _queue: &mut dyn ActionBufferQueue,
236 ) {
237 let world = unsafe { world.as_ref() };
239
240 #[cfg(debug_assertions)]
241 release(self.query, self.filter, world.archetypes());
242
243 self.query.after(world);
244 self.filter.after(world);
245 }
246}
247
248#[test]
249fn test_system() {
250 fn foo(_: ViewCell<&u32>) {}
251 fn is_system<M, T: super::IntoSystem<M>>(_: T) {}
252 is_system(foo);
253}