use core::marker::PhantomData;
use crate::entities::EntityMeta;
use crate::query::{assert_borrow, Fetch, With, Without};
use crate::QueryOneError;
use crate::{Archetype, Query};
pub struct QueryOne<'a, Q: Query> {
meta: &'a [EntityMeta],
archetype: Option<&'a Archetype>,
index: u32,
borrowed: bool,
_marker: PhantomData<Q>,
}
impl<'a, Q: Query> QueryOne<'a, Q> {
pub(crate) unsafe fn new(meta: &'a [EntityMeta], archetype: &'a Archetype, index: u32) -> Self {
Self {
meta,
archetype: Some(archetype),
index,
borrowed: false,
_marker: PhantomData,
}
}
pub fn get(&mut self) -> Result<Q::Item<'_>, QueryOneError> {
assert_borrow::<Q>();
if self.borrowed {
panic!("called QueryOnce::get twice; construct a new query instead");
}
let archetype = self.archetype.as_ref().ok_or(QueryOneError::NoSuchEntity)?;
let state = Q::Fetch::prepare(archetype).ok_or(QueryOneError::Unsatisfied)?;
Q::Fetch::borrow(archetype, state);
let fetch = Q::Fetch::execute(archetype, state);
self.borrowed = true;
unsafe { Ok(Q::get(self.meta, &fetch, self.index as usize)) }
}
pub fn with<R: Query>(self) -> QueryOne<'a, With<Q, R>> {
self.transform()
}
pub fn without<R: Query>(self) -> QueryOne<'a, Without<Q, R>> {
self.transform()
}
fn transform<R: Query>(mut self) -> QueryOne<'a, R> {
let x = QueryOne {
meta: self.meta,
archetype: self.archetype,
index: self.index,
borrowed: self.borrowed,
_marker: PhantomData,
};
self.borrowed = false;
x
}
}
impl<Q: Query> Default for QueryOne<'_, Q> {
fn default() -> Self {
Self {
meta: &[],
archetype: None,
index: 0,
borrowed: false,
_marker: PhantomData,
}
}
}
impl<Q: Query> Drop for QueryOne<'_, Q> {
fn drop(&mut self) {
if self.borrowed {
let state = Q::Fetch::prepare(self.archetype.unwrap()).unwrap();
Q::Fetch::release(self.archetype.unwrap(), state);
}
}
}
unsafe impl<Q: Query> Send for QueryOne<'_, Q> {}
unsafe impl<Q: Query> Sync for QueryOne<'_, Q> {}