1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87
use core::marker::PhantomData;
use crate::query::{assert_borrow, Fetch, With, Without};
use crate::{Archetype, Query};
/// A borrow of a [`World`](crate::World) sufficient to execute the query `Q` on a single entity
pub struct QueryOne<'a, Q: Query> {
archetype: &'a Archetype,
index: u32,
borrowed: bool,
_marker: PhantomData<Q>,
}
impl<'a, Q: Query> QueryOne<'a, Q> {
/// Construct a query accessing the entity in `archetype` at `index`
///
/// # Safety
///
/// `index` must be in-bounds for `archetype`
pub(crate) unsafe fn new(archetype: &'a Archetype, index: u32) -> Self {
assert_borrow::<Q>();
Self {
archetype,
index,
borrowed: false,
_marker: PhantomData,
}
}
/// Get the query result, or `None` if the entity does not satisfy the query
///
/// Must be called at most once.
///
/// Panics if called more than once or if it would construct a borrow that clashes with another
/// pre-existing borrow.
// Note that this uses self's lifetime, not 'a, for soundness.
pub fn get(&mut self) -> Option<Q::Item<'_>> {
if self.borrowed {
panic!("called QueryOnce::get twice; construct a new query instead");
}
let state = Q::Fetch::prepare(self.archetype)?;
Q::Fetch::borrow(self.archetype, state);
let fetch = Q::Fetch::execute(self.archetype, state);
self.borrowed = true;
unsafe { Some(Q::get(&fetch, self.index as usize)) }
}
/// Transform the query into one that requires another query be satisfied
///
/// See `QueryBorrow::with`
pub fn with<R: Query>(self) -> QueryOne<'a, With<Q, R>> {
self.transform()
}
/// Transform the query into one that skips entities satisfying another
///
/// See `QueryBorrow::without` for details.
pub fn without<R: Query>(self) -> QueryOne<'a, Without<Q, R>> {
self.transform()
}
/// Helper to change the type of the query
fn transform<R: Query>(mut self) -> QueryOne<'a, R> {
let x = QueryOne {
archetype: self.archetype,
index: self.index,
borrowed: self.borrowed,
_marker: PhantomData,
};
// Ensure `Drop` won't fire redundantly
self.borrowed = false;
x
}
}
impl<Q: Query> Drop for QueryOne<'_, Q> {
fn drop(&mut self) {
if self.borrowed {
let state = Q::Fetch::prepare(self.archetype).unwrap();
Q::Fetch::release(self.archetype, state);
}
}
}
unsafe impl<Q: Query> Send for QueryOne<'_, Q> {}
unsafe impl<Q: Query> Sync for QueryOne<'_, Q> {}