mewo_ecs/galaxy/
query.rs

1use super::{
2    ComponentAccessOptional, ComponentAccessesNormal, ComponentAccessesOptional, Entity, Galaxy,
3    QueryAccess, QueryFilterType, QueryId, QueryLockType,
4};
5use std::marker::PhantomData;
6
7//  TODO OPT: Don't write lock storages if they are len == 0.
8
9pub 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        //  Order doesn't matter does it?
112        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    //  Call after next.
137    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}