edict/query/borrow/
all.rs

1use alloc::rc::Rc;
2use core::{any::TypeId, fmt::Debug, iter::FusedIterator, marker::PhantomData, ptr::NonNull};
3
4use crate::{
5    archetype::Archetype,
6    component::{BorrowFn, BorrowFnMut, ComponentInfo},
7    epoch::EpochId,
8    query::{
9        read::Read, Access, AsQuery, DefaultQuery, Fetch, ImmutableQuery, IntoQuery, Query,
10        SendQuery, Write, WriteAlias,
11    },
12    system::QueryArg,
13    type_id,
14};
15
16/// Query that borrows from components.
17#[derive(Clone, Copy, Debug, Default)]
18pub struct QueryBorrowAll<T>(pub T);
19
20struct FetchBorrowAllComponent<T: ?Sized> {
21    ptr: NonNull<u8>,
22    size: usize,
23    borrow_fn: BorrowFn<T>,
24    borrow_mut_fn: Option<BorrowFnMut<T>>,
25    entity_epochs: NonNull<EpochId>,
26    chunk_epochs: NonNull<EpochId>,
27}
28
29impl<T> Clone for FetchBorrowAllComponent<T>
30where
31    T: ?Sized,
32{
33    #[inline(always)]
34    fn clone(&self) -> Self {
35        *self
36    }
37}
38
39impl<T> Copy for FetchBorrowAllComponent<T> where T: ?Sized {}
40
41pub struct BorrowAllRead<'a, T: ?Sized> {
42    idx: u32,
43    comp_idx: usize,
44    components: Rc<[FetchBorrowAllComponent<T>]>,
45    marker: PhantomData<&'a T>,
46}
47
48impl<'a, T> Clone for BorrowAllRead<'a, T>
49where
50    T: ?Sized,
51{
52    #[inline(always)]
53    fn clone(&self) -> Self {
54        BorrowAllRead {
55            idx: self.idx,
56            comp_idx: self.comp_idx,
57            components: self.components.clone(),
58            marker: self.marker,
59        }
60    }
61
62    #[inline(always)]
63    fn clone_from(&mut self, source: &Self) {
64        self.idx = source.idx;
65        self.comp_idx = source.comp_idx;
66        self.components = source.components.clone();
67    }
68}
69
70impl<'a, T> Debug for BorrowAllRead<'a, T>
71where
72    T: Debug + ?Sized,
73{
74    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
75        f.debug_list().entries(self.clone()).finish()
76    }
77}
78
79impl<'a, T> Iterator for BorrowAllRead<'a, T>
80where
81    T: ?Sized,
82{
83    type Item = &'a T;
84
85    #[inline(always)]
86    fn size_hint(&self) -> (usize, Option<usize>) {
87        let len = self.len();
88        (len, Some(len))
89    }
90
91    #[inline(always)]
92    fn next(&mut self) -> Option<&'a T> {
93        let c = &self.components.get(self.comp_idx)?;
94        let r = unsafe {
95            (c.borrow_fn)(
96                NonNull::new_unchecked(c.ptr.as_ptr().add(self.idx as usize * c.size)),
97                self.marker,
98            )
99        };
100        self.comp_idx += 1;
101        Some(r)
102    }
103
104    #[inline(always)]
105    fn nth(&mut self, n: usize) -> Option<&'a T> {
106        if n >= self.components.len() - self.comp_idx {
107            self.comp_idx = self.components.len();
108        } else {
109            self.comp_idx += n;
110        }
111        self.next()
112    }
113
114    fn fold<B, F>(mut self, init: B, mut f: F) -> B
115    where
116        Self: Sized,
117        F: FnMut(B, &'a T) -> B,
118    {
119        let mut accum = init;
120        for comp_idx in self.comp_idx..self.components.len() {
121            let c = &self.components[comp_idx];
122            let r = unsafe {
123                (c.borrow_fn)(
124                    NonNull::new_unchecked(c.ptr.as_ptr().add(self.idx as usize * c.size)),
125                    self.marker,
126                )
127            };
128            self.comp_idx += 1;
129            accum = f(accum, r);
130        }
131        accum
132    }
133}
134
135impl<'a, T> ExactSizeIterator for BorrowAllRead<'a, T>
136where
137    T: ?Sized,
138{
139    #[inline(always)]
140    fn len(&self) -> usize {
141        self.components.len() - self.comp_idx
142    }
143}
144
145impl<'a, T> FusedIterator for BorrowAllRead<'a, T> where T: ?Sized {}
146
147/// [`Fetch`] for [`QueryBorrowAll<&T>`].
148pub struct FetchBorrowAllRead<'a, T: ?Sized> {
149    components: Rc<[FetchBorrowAllComponent<T>]>,
150    marker: PhantomData<&'a T>,
151}
152
153unsafe impl<'a, T> Fetch<'a> for FetchBorrowAllRead<'a, T>
154where
155    T: ?Sized + 'a,
156{
157    type Item = BorrowAllRead<'a, T>;
158
159    #[inline(always)]
160    fn dangling() -> Self {
161        FetchBorrowAllRead {
162            components: Rc::new([]),
163            marker: PhantomData,
164        }
165    }
166
167    #[inline(always)]
168    unsafe fn get_item(&mut self, idx: u32) -> BorrowAllRead<'a, T> {
169        BorrowAllRead {
170            idx,
171            comp_idx: 0,
172            components: self.components.clone(),
173            marker: self.marker,
174        }
175    }
176}
177
178impl<T> AsQuery for QueryBorrowAll<&T>
179where
180    T: ?Sized + 'static,
181{
182    type Query = QueryBorrowAll<Read<T>>;
183}
184
185impl<T> DefaultQuery for QueryBorrowAll<&T>
186where
187    T: ?Sized + 'static,
188{
189    #[inline(always)]
190    fn default_query() -> QueryBorrowAll<Read<T>> {
191        QueryBorrowAll(Read)
192    }
193}
194
195impl<T> AsQuery for QueryBorrowAll<Read<T>>
196where
197    T: ?Sized + 'static,
198{
199    type Query = Self;
200}
201
202impl<T> IntoQuery for QueryBorrowAll<Read<T>>
203where
204    T: ?Sized + 'static,
205{
206    #[inline(always)]
207    fn into_query(self) -> Self {
208        self
209    }
210}
211
212impl<T> DefaultQuery for QueryBorrowAll<Read<T>>
213where
214    T: ?Sized + 'static,
215{
216    #[inline(always)]
217    fn default_query() -> Self {
218        QueryBorrowAll(Read)
219    }
220}
221
222impl<T> QueryArg for QueryBorrowAll<Read<T>>
223where
224    T: Sync + ?Sized + 'static,
225{
226    #[inline(always)]
227    fn new() -> Self {
228        QueryBorrowAll(Read)
229    }
230}
231
232unsafe impl<T> Query for QueryBorrowAll<Read<T>>
233where
234    T: ?Sized + 'static,
235{
236    type Item<'a> = BorrowAllRead<'a, T>;
237    type Fetch<'a> = FetchBorrowAllRead<'a, T>;
238
239    const MUTABLE: bool = false;
240
241    #[inline(always)]
242    fn component_access(&self, comp: &ComponentInfo) -> Result<Option<Access>, WriteAlias> {
243        if comp.has_borrow(type_id::<T>()) {
244            Ok(Some(Access::Read))
245        } else {
246            Ok(None)
247        }
248    }
249
250    #[inline(always)]
251    fn visit_archetype(&self, archetype: &Archetype) -> bool {
252        archetype.contains_borrow(type_id::<T>())
253    }
254
255    #[inline(always)]
256    unsafe fn access_archetype(&self, archetype: &Archetype, mut f: impl FnMut(TypeId, Access)) {
257        let indices = unsafe { archetype.borrow_indices(type_id::<T>()).unwrap_unchecked() };
258        for (id, _) in indices {
259            f(*id, Access::Read);
260        }
261    }
262
263    #[inline(always)]
264    unsafe fn fetch<'a>(
265        &self,
266        _arch_idx: u32,
267        archetype: &'a Archetype,
268        _epoch: EpochId,
269    ) -> FetchBorrowAllRead<'a, T> {
270        let indices = unsafe { archetype.borrow_indices(type_id::<T>()).unwrap_unchecked() };
271        let components = indices
272            .iter()
273            .map(|&(id, idx)| {
274                let component = unsafe { archetype.component(id).unwrap_unchecked() };
275                debug_assert_eq!(component.borrows()[idx].target(), type_id::<T>());
276
277                let data = unsafe { component.data_mut() };
278
279                FetchBorrowAllComponent {
280                    ptr: data.ptr,
281                    size: component.layout().size(),
282                    borrow_fn: component.borrows()[idx].borrow(),
283                    borrow_mut_fn: None,
284                    entity_epochs: NonNull::new_unchecked(data.entity_epochs.as_mut_ptr()),
285                    chunk_epochs: NonNull::new_unchecked(data.chunk_epochs.as_mut_ptr()),
286                }
287            })
288            .collect();
289
290        FetchBorrowAllRead {
291            components,
292            marker: PhantomData::<&'a T>,
293        }
294    }
295}
296
297unsafe impl<T> ImmutableQuery for QueryBorrowAll<Read<T>> where T: ?Sized + 'static {}
298unsafe impl<T> SendQuery for QueryBorrowAll<Read<T>> where T: Sync + ?Sized + 'static {}
299
300pub struct BorrowAllWrite<'a, T: ?Sized> {
301    idx: u32,
302    epoch: EpochId,
303    comp_idx: usize,
304    components: Rc<[FetchBorrowAllComponent<T>]>,
305    marker: PhantomData<&'a mut T>,
306}
307
308impl<'a, T> BorrowAllWrite<'a, T>
309where
310    T: ?Sized,
311{
312    /// Borrow write iterator as read iterator.
313    ///
314    /// Returned read iteartor will yield shared reference to the components
315    /// and may be iterated multiple times.
316    /// It won't yield components that were already yielded by this iterator.
317    ///
318    /// After all copies of returned read iterator are dropped, write iterator
319    /// will be able to yield mutable reference to components that were yielded by read iterator.
320    pub fn read(&self) -> BorrowAllRead<'_, T> {
321        BorrowAllRead {
322            idx: self.idx,
323            comp_idx: self.comp_idx,
324            components: self.components.clone(),
325            marker: PhantomData::<&T>,
326        }
327    }
328
329    /// Turn write iterator into read iterator.
330    ///
331    /// Returned read iteartor will yield shared reference to the components
332    /// and may be iterated multiple times.
333    /// It won't yield components that were already yielded by this iterator.
334    pub fn into_read(self) -> BorrowAllRead<'a, T> {
335        BorrowAllRead {
336            idx: self.idx,
337            comp_idx: self.comp_idx,
338            components: self.components.clone(),
339            marker: PhantomData::<&'a T>,
340        }
341    }
342}
343
344impl<T> Debug for BorrowAllWrite<'_, T>
345where
346    T: Debug + ?Sized,
347{
348    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
349        f.debug_list().entries(self.read()).finish()
350    }
351}
352
353impl<'a, T> Iterator for BorrowAllWrite<'a, T>
354where
355    T: ?Sized,
356{
357    type Item = &'a mut T;
358
359    #[inline(always)]
360    fn size_hint(&self) -> (usize, Option<usize>) {
361        let len = self.len();
362        (len, Some(len))
363    }
364
365    #[inline(always)]
366    fn next(&mut self) -> Option<&'a mut T> {
367        let c = &self.components.get(self.comp_idx)?;
368        let r = unsafe {
369            let entity_version = &mut *c.entity_epochs.as_ptr().add(self.idx as usize);
370            entity_version.bump(self.epoch);
371
372            // Safety: mutable borrow function exists. Checked in `Query::fetch`.
373            (c.borrow_mut_fn.unwrap_unchecked())(
374                NonNull::new_unchecked(c.ptr.as_ptr().add(self.idx as usize * c.size)),
375                self.marker,
376            )
377        };
378        self.comp_idx += 1;
379        Some(r)
380    }
381
382    #[inline(always)]
383    fn nth(&mut self, n: usize) -> Option<&'a mut T> {
384        if n >= self.components.len() - self.comp_idx {
385            self.comp_idx = self.components.len();
386        } else {
387            self.comp_idx += n;
388        }
389        self.next()
390    }
391
392    fn fold<B, F>(mut self, init: B, mut f: F) -> B
393    where
394        Self: Sized,
395        F: FnMut(B, &'a mut T) -> B,
396    {
397        let mut accum = init;
398        for comp_idx in self.comp_idx..self.components.len() {
399            let c = &self.components[comp_idx];
400
401            let r = unsafe {
402                let entity_version = &mut *c.entity_epochs.as_ptr().add(self.idx as usize);
403                entity_version.bump(self.epoch);
404
405                // Safety: mutable borrow function exists. Checked in `Query::fetch`.
406                (c.borrow_mut_fn.unwrap_unchecked())(
407                    NonNull::new_unchecked(c.ptr.as_ptr().add(self.idx as usize * c.size)),
408                    self.marker,
409                )
410            };
411            self.comp_idx += 1;
412            accum = f(accum, r);
413        }
414        accum
415    }
416}
417
418impl<'a, T> ExactSizeIterator for BorrowAllWrite<'a, T>
419where
420    T: ?Sized,
421{
422    #[inline(always)]
423    fn len(&self) -> usize {
424        self.components.len() - self.comp_idx
425    }
426}
427
428impl<'a, T> FusedIterator for BorrowAllWrite<'a, T> where T: ?Sized {}
429
430/// [`Fetch`] for [`QueryBorrowAll<&mut T>`].
431pub struct FetchBorrowAllWrite<'a, T: ?Sized> {
432    components: Rc<[FetchBorrowAllComponent<T>]>,
433    epoch: EpochId,
434    marker: PhantomData<&'a mut T>,
435}
436
437unsafe impl<'a, T> Fetch<'a> for FetchBorrowAllWrite<'a, T>
438where
439    T: ?Sized + 'a,
440{
441    type Item = BorrowAllWrite<'a, T>;
442
443    #[inline(always)]
444    fn dangling() -> Self {
445        FetchBorrowAllWrite {
446            components: Rc::new([]),
447            epoch: EpochId::start(),
448            marker: PhantomData,
449        }
450    }
451
452    #[inline(always)]
453    unsafe fn touch_chunk(&mut self, chunk_idx: u32) {
454        self.components.iter().for_each(|c| {
455            let chunk_epoch = &mut *c.chunk_epochs.as_ptr().add(chunk_idx as usize);
456            chunk_epoch.bump(self.epoch);
457        })
458    }
459
460    #[inline(always)]
461    unsafe fn get_item(&mut self, idx: u32) -> BorrowAllWrite<'a, T> {
462        BorrowAllWrite {
463            idx,
464            epoch: self.epoch,
465            comp_idx: 0,
466            components: self.components.clone(),
467            marker: self.marker,
468        }
469    }
470}
471
472impl<T> AsQuery for QueryBorrowAll<&mut T>
473where
474    T: ?Sized + 'static,
475{
476    type Query = QueryBorrowAll<Write<T>>;
477}
478
479impl<T> DefaultQuery for QueryBorrowAll<&mut T>
480where
481    T: ?Sized + 'static,
482{
483    #[inline(always)]
484    fn default_query() -> QueryBorrowAll<Write<T>> {
485        QueryBorrowAll(Write)
486    }
487}
488
489impl<T> AsQuery for QueryBorrowAll<Write<T>>
490where
491    T: ?Sized + 'static,
492{
493    type Query = Self;
494}
495
496impl<T> IntoQuery for QueryBorrowAll<Write<T>>
497where
498    T: ?Sized + 'static,
499{
500    #[inline(always)]
501    fn into_query(self) -> Self {
502        self
503    }
504}
505
506impl<T> DefaultQuery for QueryBorrowAll<Write<T>>
507where
508    T: ?Sized + 'static,
509{
510    #[inline(always)]
511    fn default_query() -> Self {
512        QueryBorrowAll(Write)
513    }
514}
515
516impl<T> QueryArg for QueryBorrowAll<Write<T>>
517where
518    T: Send + ?Sized + 'static,
519{
520    #[inline(always)]
521    fn new() -> Self {
522        QueryBorrowAll(Write)
523    }
524}
525
526unsafe impl<T> Query for QueryBorrowAll<Write<T>>
527where
528    T: ?Sized + 'static,
529{
530    type Item<'a> = BorrowAllWrite<'a, T>;
531    type Fetch<'a> = FetchBorrowAllWrite<'a, T>;
532
533    const MUTABLE: bool = true;
534
535    #[inline(always)]
536    fn component_access(&self, comp: &ComponentInfo) -> Result<Option<Access>, WriteAlias> {
537        if comp.has_borrow_mut(type_id::<T>()) {
538            Ok(Some(Access::Write))
539        } else {
540            Ok(None)
541        }
542    }
543
544    #[inline(always)]
545    fn visit_archetype(&self, archetype: &Archetype) -> bool {
546        archetype.contains_borrow_mut(type_id::<T>())
547    }
548
549    #[inline(always)]
550    unsafe fn access_archetype(&self, archetype: &Archetype, mut f: impl FnMut(TypeId, Access)) {
551        let indices = unsafe {
552            archetype
553                .borrow_mut_indices(type_id::<T>())
554                .unwrap_unchecked()
555        };
556        for (id, _) in indices {
557            f(*id, Access::Write);
558        }
559    }
560
561    #[inline(always)]
562    unsafe fn fetch<'a>(
563        &self,
564        _arch_idx: u32,
565        archetype: &'a Archetype,
566        epoch: EpochId,
567    ) -> FetchBorrowAllWrite<'a, T> {
568        let indices = unsafe {
569            archetype
570                .borrow_mut_indices(type_id::<T>())
571                .unwrap_unchecked()
572        };
573        let components = indices
574            .iter()
575            .map(|&(id, idx)| {
576                let component = unsafe { archetype.component(id).unwrap_unchecked() };
577                debug_assert_eq!(component.borrows()[idx].target(), type_id::<T>());
578                debug_assert!(component.borrows()[idx].borrow_mut::<T>().is_some());
579
580                let data = unsafe { component.data_mut() };
581                data.epoch.bump(epoch);
582
583                FetchBorrowAllComponent {
584                    ptr: data.ptr,
585                    size: component.layout().size(),
586                    borrow_fn: component.borrows()[idx].borrow(),
587                    borrow_mut_fn: component.borrows()[idx].borrow_mut(),
588                    entity_epochs: NonNull::new_unchecked(data.entity_epochs.as_mut_ptr()),
589                    chunk_epochs: NonNull::new_unchecked(data.chunk_epochs.as_mut_ptr()),
590                }
591            })
592            .collect();
593
594        FetchBorrowAllWrite {
595            components,
596            epoch,
597            marker: PhantomData::<&'a mut T>,
598        }
599    }
600}
601
602unsafe impl<T> SendQuery for QueryBorrowAll<Write<T>> where T: Send + ?Sized + 'static {}