1use super::{
2 ComponentAccessOptional, ComponentAccessesNormal, ComponentAccessesOptional, Entity, Galaxy,
3 QueryAccess, QueryFilterType, QueryId, QueryLockType,
4};
5use std::marker::PhantomData;
6
7pub struct QueryInfo<'gal, CA> {
10 incomplete: QueryAccess,
11 galaxy: &'gal Galaxy,
12 phantom: PhantomData<CA>,
13}
14
15impl<'gal, CA> QueryInfo<'gal, CA>
16where
17 CA: ComponentAccessOptional,
18{
19 pub fn with<CF: ComponentAccessesNormal>(mut self) -> Self {
20 CF::component_maybe_insert(&self.galaxy.ctyp);
21 self.incomplete.filters.append(
22 &mut CF::hashes()
23 .into_iter()
24 .map(|cty| (cty, QueryFilterType::With))
25 .collect(),
26 );
27 self
28 }
29
30 pub fn without<CF: ComponentAccessesNormal>(mut self) -> Self {
31 CF::component_maybe_insert(&self.galaxy.ctyp);
32 self.incomplete.filters.append(
33 &mut CF::hashes()
34 .into_iter()
35 .map(|cty| (cty, QueryFilterType::Without))
36 .collect(),
37 );
38 self
39 }
40
41 pub fn iter(self) -> QueryIter<'gal, CA> {
42 let Self {
43 incomplete,
44 galaxy,
45 phantom,
46 } = self;
47 let _ = phantom;
48 QueryIter {
49 galaxy,
50 qid: {
51 let maybe_qid = galaxy.qp.read().get_query_id(&incomplete);
52 if let Some(qid) = maybe_qid {
53 qid
54 } else {
55 let mut qp = self.galaxy.qp.write();
56 qp.insert_access(
57 &self.galaxy.ctyp,
58 &self.galaxy.cgp,
59 &self.galaxy.sp,
60 incomplete,
61 )
62 .unwrap()
63 }
64 },
65 current_storage: None,
66 current_datas: None,
67 current_entities: None,
68 current_storage_len: None,
69 group_idx: 0,
70 storage_idx: 0,
71 phantom: PhantomData,
72 }
73 }
74
75 pub fn eiter(self) -> QueryEIter<'gal, CA> {
76 QueryEIter { qiter: self.iter() }
77 }
78}
79
80struct QueryStorageGuard<'gal> {
81 qid: QueryId,
82 group_idx: usize,
83 galaxy: &'gal Galaxy,
84}
85
86impl<'gal> QueryStorageGuard<'gal> {
87 pub fn new(qid: QueryId, group_idx: usize, galaxy: &'gal Galaxy) -> Self {
88 let qp = galaxy.qp.read();
89 let access = qp.get_access(qid).unwrap();
90 let (gid, ord, locks) = &access.groups[group_idx];
91 for cty in ord.get_components().iter() {
92 let lock = locks.get(cty).unwrap();
93 match lock {
94 QueryLockType::Read => galaxy.sp.read().get_read_lock(*gid, *cty),
95 QueryLockType::Write => galaxy.sp.read().get_write_lock(*gid, *cty),
96 }
97 .unwrap();
98 }
99 QueryStorageGuard {
100 qid,
101 group_idx,
102 galaxy,
103 }
104 }
105}
106
107impl<'gal> Drop for QueryStorageGuard<'gal> {
108 fn drop(&mut self) {
109 let qp = self.galaxy.qp.read();
110 let access = qp.get_access(self.qid).unwrap();
111 let (gid, _, locks) = &access.groups[self.group_idx];
113 for (cty, lock) in locks {
114 match lock {
115 QueryLockType::Read => self.galaxy.sp.read().get_read_unlock(*gid, *cty),
116 QueryLockType::Write => self.galaxy.sp.read().get_write_unlock(*gid, *cty),
117 }
118 .unwrap();
119 }
120 }
121}
122
123pub struct QueryIter<'gal, CA> {
124 galaxy: &'gal Galaxy,
125 qid: QueryId,
126 current_storage: Option<QueryStorageGuard<'gal>>,
127 current_datas: Option<Vec<Option<*const u8>>>,
128 current_entities: Option<*const Entity>,
129 current_storage_len: Option<usize>,
130 group_idx: usize,
131 storage_idx: usize,
132 phantom: PhantomData<CA>,
133}
134
135impl<'gal, CA> QueryIter<'gal, CA> {
136 pub fn get_current_entity(&self) -> Entity {
138 unsafe { *self.current_entities.unwrap().add(self.storage_idx - 1) }
139 }
140}
141
142impl<'gal, CA> Iterator for QueryIter<'gal, CA>
143where
144 CA: ComponentAccessesOptional,
145{
146 type Item = CA;
147
148 fn next(&mut self) -> Option<Self::Item> {
149 let qp = self.galaxy.qp.read();
150 let access = qp.get_access(self.qid).unwrap();
151
152 if access.groups.len() == self.group_idx {
153 None?
154 }
155
156 let (gid, ord, locks) = &access.groups[self.group_idx];
157
158 if self.current_storage.is_none() {
159 self.current_storage_len = Some(self.galaxy.sp.read().get_len(*gid));
160 self.current_storage = Some(QueryStorageGuard::new(
161 self.qid,
162 self.group_idx,
163 self.galaxy,
164 ));
165 let sp = self.galaxy.sp.read();
166 self.current_datas = Some(
167 ord.get_components()
168 .iter()
169 .map(|cid| {
170 let lock = locks.get(cid).unwrap();
171 match lock {
172 QueryLockType::Read => sp.get_read(*gid, *cid),
173 QueryLockType::Write => sp.get_write(*gid, *cid),
174 }
175 })
176 .collect(),
177 );
178 self.current_entities = Some(sp.get_entities(*gid).unwrap());
179 self.storage_idx = 0;
180 }
181
182 if self.storage_idx == self.current_storage_len.unwrap() {
183 self.group_idx += 1;
184 self.current_storage = None;
185 self.current_datas = None;
186 self.current_storage_len = None;
187 return self.next();
188 }
189 let ret = CA::datas(self.current_datas.as_ref().unwrap(), self.storage_idx);
190 self.storage_idx += 1;
191 Some(ret)
192 }
193}
194
195pub struct QueryEIter<'gal, CA> {
196 qiter: QueryIter<'gal, CA>,
197}
198
199impl<'gal, CA> Iterator for QueryEIter<'gal, CA>
200where
201 CA: ComponentAccessesOptional,
202{
203 type Item = (Entity, CA);
204
205 fn next(&mut self) -> Option<Self::Item> {
206 let next = self.qiter.next()?;
207 let entity = self.qiter.get_current_entity();
208 Some((entity, next))
209 }
210}
211
212impl Galaxy {
213 pub fn query<CA: ComponentAccessOptional>(&self) -> QueryInfo<CA> {
214 CA::component_maybe_insert(&self.ctyp);
215 QueryInfo {
216 incomplete: QueryAccess {
217 accesses: CA::infos(),
218 filters: Vec::new(),
219 },
220 galaxy: self,
221 phantom: PhantomData,
222 }
223 }
224}