use super::{
query::{
EntQueryInfo, EntQueryKey, EntQueryMut, Query, QueryInfo, QueryKey, QueryMut, ResQuery,
ResQueryInfo, ResQueryKey, ResQueryMut, StoreEntQueryInfo, StoreQueryInfo,
StoreResQueryInfo,
},
select::{
FilterInfo, FilterKey, FilteredRaw, SelectInfo, SelectKey, SelectedRaw, StoreFilterInfo,
StoreSelectInfo,
},
};
use crate::{
ecs::resource::ResourceKey,
utils::ds::{ATypeId, Borrowed, ManagedConstPtr, ManagedMutPtr},
FxBuildHasher,
};
use my_utils::debug_format;
use once_cell::sync::Lazy;
use std::{
any,
collections::HashMap,
fmt,
hash::BuildHasher,
marker::PhantomData,
sync::{Arc, Mutex},
};
pub(crate) static RINFO_STOR: Lazy<Arc<Mutex<RequestInfoStorage<FxBuildHasher>>>> =
Lazy::new(|| Arc::new(Mutex::new(RequestInfoStorage::new())));
#[derive(Debug)]
pub(crate) struct RequestInfoStorage<S> {
rinfo: HashMap<RequestKey, Arc<RequestInfo>, S>,
qinfo: HashMap<QueryKey, Arc<QueryInfo>, S>,
rqinfo: HashMap<ResQueryKey, Arc<ResQueryInfo>, S>,
eqinfo: HashMap<EntQueryKey, Arc<EntQueryInfo>, S>,
sinfo: HashMap<SelectKey, Arc<SelectInfo>, S>,
finfo: HashMap<FilterKey, Arc<FilterInfo>, S>,
}
impl<S> RequestInfoStorage<S>
where
S: Default,
{
fn new() -> Self {
Self {
rinfo: HashMap::default(),
qinfo: HashMap::default(),
rqinfo: HashMap::default(),
eqinfo: HashMap::default(),
sinfo: HashMap::default(),
finfo: HashMap::default(),
}
}
}
impl<S> RequestInfoStorage<S>
where
S: BuildHasher,
{
#[allow(dead_code)]
pub(crate) fn get_request_info(&self, key: &RequestKey) -> Option<&Arc<RequestInfo>> {
StoreRequestInfo::get(self, key)
}
#[allow(dead_code)]
pub(crate) fn get_query_info(&self, key: &QueryKey) -> Option<&Arc<QueryInfo>> {
StoreQueryInfo::get(self, key)
}
#[allow(dead_code)]
pub(crate) fn get_resource_query_info(&self, key: &ResQueryKey) -> Option<&Arc<ResQueryInfo>> {
StoreResQueryInfo::get(self, key)
}
#[allow(dead_code)]
pub(crate) fn get_entity_query_info(&self, key: &EntQueryKey) -> Option<&Arc<EntQueryInfo>> {
StoreEntQueryInfo::get(self, key)
}
#[allow(dead_code)]
pub(crate) fn get_select_info(&self, key: &SelectKey) -> Option<&Arc<SelectInfo>> {
StoreSelectInfo::get(self, key)
}
#[allow(dead_code)]
pub(crate) fn get_filter_info(&self, key: &FilterKey) -> Option<&Arc<FilterInfo>> {
StoreFilterInfo::get(self, key)
}
fn remove(&mut self, key: &RequestKey) {
if matches!(self.rinfo.get(key), Some(x) if Arc::strong_count(x) == 1) {
let rinfo = unsafe { self.rinfo.remove(key).unwrap_unchecked() };
let read_key = rinfo.read().0;
let write_key = rinfo.write().0;
let res_read_key = rinfo.res_read().0;
let res_write_key = rinfo.res_write().0;
let ent_write_key = rinfo.ent_write().0;
drop(rinfo);
remove_qinfo_sinfo(self, &read_key);
remove_qinfo_sinfo(self, &write_key);
remove_rqinfo(self, &res_read_key);
remove_rqinfo(self, &res_write_key);
remove_eqinfo(self, &ent_write_key);
}
fn remove_qinfo_sinfo<S>(this: &mut RequestInfoStorage<S>, key: &QueryKey)
where
S: BuildHasher,
{
const QINFO_EMPTY_STRONG_CNT: usize = 1;
if matches! (
this.qinfo.get(key),
Some(x) if Arc::strong_count(x) == QINFO_EMPTY_STRONG_CNT
) {
let qinfo = unsafe { this.qinfo.remove(key).unwrap_unchecked() };
for (fkey, sinfo) in qinfo.selectors() {
const FINFO_EMPTY_STRONG_CNT: usize = 2;
if Arc::strong_count(sinfo) == FINFO_EMPTY_STRONG_CNT {
this.sinfo.remove(fkey);
}
}
}
}
fn remove_rqinfo<S>(this: &mut RequestInfoStorage<S>, key: &ResQueryKey)
where
S: BuildHasher,
{
const EMPTY_STRONG_CNT: usize = 1;
if matches! (
this.rqinfo.get(key),
Some(x) if Arc::strong_count(x) == EMPTY_STRONG_CNT
) {
this.rqinfo.remove(key);
}
}
fn remove_eqinfo<S>(this: &mut RequestInfoStorage<S>, key: &EntQueryKey)
where
S: BuildHasher,
{
const EMPTY_STRONG_CNT: usize = 1;
if matches! (
this.eqinfo.get(key),
Some(x) if Arc::strong_count(x) == EMPTY_STRONG_CNT
) {
this.eqinfo.remove(key);
}
}
}
}
impl<S> Default for RequestInfoStorage<S>
where
S: Default,
{
fn default() -> Self {
Self::new()
}
}
impl<S> StoreRequestInfo for RequestInfoStorage<S>
where
S: BuildHasher,
{
fn contains(&self, key: &RequestKey) -> bool {
self.rinfo.contains_key(key)
}
fn get(&self, key: &RequestKey) -> Option<&Arc<RequestInfo>> {
self.rinfo.get(key)
}
fn insert(&mut self, key: RequestKey, info: Arc<RequestInfo>) {
self.rinfo.insert(key, info);
}
fn remove(&mut self, key: &RequestKey) {
self.remove(key)
}
}
impl<S> StoreQueryInfo for RequestInfoStorage<S>
where
S: BuildHasher,
{
fn contains(&self, key: &QueryKey) -> bool {
self.qinfo.contains_key(key)
}
fn get(&self, key: &QueryKey) -> Option<&Arc<QueryInfo>> {
self.qinfo.get(key)
}
fn insert(&mut self, key: QueryKey, info: Arc<QueryInfo>) {
self.qinfo.insert(key, info);
}
}
impl<S> StoreResQueryInfo for RequestInfoStorage<S>
where
S: BuildHasher,
{
fn contains(&self, key: &ResQueryKey) -> bool {
self.rqinfo.contains_key(key)
}
fn get(&self, key: &ResQueryKey) -> Option<&Arc<ResQueryInfo>> {
self.rqinfo.get(key)
}
fn insert(&mut self, key: ResQueryKey, info: Arc<ResQueryInfo>) {
self.rqinfo.insert(key, info);
}
}
impl<S> StoreEntQueryInfo for RequestInfoStorage<S>
where
S: BuildHasher,
{
fn contains(&self, key: &EntQueryKey) -> bool {
self.eqinfo.contains_key(key)
}
fn get(&self, key: &EntQueryKey) -> Option<&Arc<EntQueryInfo>> {
self.eqinfo.get(key)
}
fn insert(&mut self, key: EntQueryKey, info: Arc<EntQueryInfo>) {
self.eqinfo.insert(key, info);
}
}
impl<S> StoreSelectInfo for RequestInfoStorage<S>
where
S: BuildHasher,
{
fn contains(&self, key: &SelectKey) -> bool {
self.sinfo.contains_key(key)
}
fn get(&self, key: &SelectKey) -> Option<&Arc<SelectInfo>> {
self.sinfo.get(key)
}
fn insert(&mut self, key: SelectKey, info: Arc<SelectInfo>) {
self.sinfo.insert(key, info);
}
}
impl<S> StoreFilterInfo for RequestInfoStorage<S>
where
S: BuildHasher,
{
fn contains(&self, key: &FilterKey) -> bool {
self.finfo.contains_key(key)
}
fn get(&self, key: &FilterKey) -> Option<&Arc<FilterInfo>> {
self.finfo.get(key)
}
fn insert(&mut self, key: FilterKey, info: Arc<FilterInfo>) {
self.finfo.insert(key, info);
}
}
pub trait Request: 'static {
type Read: Query;
type Write: QueryMut;
type ResRead: ResQuery;
type ResWrite: ResQueryMut;
type EntWrite: EntQueryMut;
#[doc(hidden)]
fn key() -> RequestKey {
RequestKey::of::<Self>()
}
#[doc(hidden)]
fn get_info_from<S>(stor: &mut S) -> &Arc<RequestInfo>
where
S: StoreRequestInfo + ?Sized,
{
let key = Self::key();
if !StoreRequestInfo::contains(stor, &key) {
let rinfo = Arc::new(Self::info_from(stor));
StoreRequestInfo::insert(stor, key, rinfo);
}
unsafe { StoreRequestInfo::get(stor, &key).unwrap_unchecked() }
}
#[doc(hidden)]
fn info_from<S>(stor: &mut S) -> RequestInfo
where
S: StoreRequestInfo + ?Sized,
{
RequestInfo {
name: any::type_name::<Self>(),
read: (
Self::Read::key(),
Arc::clone(Self::Read::get_info_from(stor)),
),
write: (
Self::Write::key(),
Arc::clone(Self::Write::get_info_from(stor)),
),
res_read: (
Self::ResRead::key(),
Arc::clone(Self::ResRead::get_info_from(stor)),
),
res_write: (
Self::ResWrite::key(),
Arc::clone(Self::ResWrite::get_info_from(stor)),
),
ent_write: (
Self::EntWrite::key(),
Arc::clone(Self::EntWrite::get_info_from(stor)),
),
}
}
}
impl<R, W, RR, RW, EW> Request for (R, W, RR, RW, EW)
where
R: Query,
W: QueryMut,
RR: ResQuery,
RW: ResQueryMut,
EW: EntQueryMut,
{
type Read = R;
type Write = W;
type ResRead = RR;
type ResWrite = RW;
type EntWrite = EW;
}
pub trait StoreRequestInfo: StoreQueryInfo + StoreResQueryInfo + StoreEntQueryInfo {
fn contains(&self, key: &RequestKey) -> bool;
fn get(&self, key: &RequestKey) -> Option<&Arc<RequestInfo>>;
fn insert(&mut self, key: RequestKey, info: Arc<RequestInfo>);
fn remove(&mut self, key: &RequestKey);
}
pub type RequestKey = ATypeId<RequestKey_>;
pub struct RequestKey_;
#[derive(Clone)]
pub struct RequestInfo {
read: (QueryKey, Arc<QueryInfo>),
write: (QueryKey, Arc<QueryInfo>),
res_read: (ResQueryKey, Arc<ResQueryInfo>),
res_write: (ResQueryKey, Arc<ResQueryInfo>),
ent_write: (EntQueryKey, Arc<EntQueryInfo>),
name: &'static str,
}
impl fmt::Debug for RequestInfo {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("RequestInfo")
.field("name", &self.name())
.field("read", &self.read())
.field("write", &self.write())
.field("res_read", &self.res_read())
.field("res_write", &self.res_write())
.field("ent_write", &self.ent_write())
.finish()
}
}
impl RequestInfo {
pub(crate) const fn read(&self) -> &(QueryKey, Arc<QueryInfo>) {
&self.read
}
pub(crate) const fn write(&self) -> &(QueryKey, Arc<QueryInfo>) {
&self.write
}
pub(crate) const fn res_read(&self) -> &(ResQueryKey, Arc<ResQueryInfo>) {
&self.res_read
}
pub(crate) const fn res_write(&self) -> &(ResQueryKey, Arc<ResQueryInfo>) {
&self.res_write
}
pub(crate) const fn ent_write(&self) -> &(EntQueryKey, Arc<EntQueryInfo>) {
&self.ent_write
}
pub(crate) const fn name(&self) -> &'static str {
self.name
}
pub(crate) fn resource_keys(&self) -> impl Iterator<Item = &ResourceKey> {
let read = self.res_read().1.as_ref();
let write = self.res_write().1.as_ref();
read.resource_keys().iter().chain(write.resource_keys())
}
pub(crate) fn filters(&self) -> &[(FilterKey, Arc<FilterInfo>)] {
self.ent_write().1.as_ref().filters()
}
pub(crate) fn validate(&self) -> Result<(), String> {
let (_, r_qinfo) = self.read();
let (_, w_qinfo) = self.write();
let r_sels = r_qinfo.selectors();
let w_sels = w_qinfo.selectors();
for i in 0..w_sels.len() {
for j in i + 1..w_sels.len() {
if !w_sels[i].1.is_disjoint(&w_sels[j].1) {
let reason = debug_format!(
"`{}` and `{}` are not disjoint in request `{}`",
w_sels[i].1.name(),
w_sels[j].1.name(),
self.name(),
);
return Err(reason);
}
}
for (_, r_sel) in r_sels.iter() {
if !w_sels[i].1.is_disjoint(r_sel) {
let reason = debug_format!(
"`{}` and `{}` are not disjoint in request `{}`",
w_sels[i].1.name(),
r_sel.name(),
self.name(),
);
return Err(reason);
}
}
}
let (_, r_rqinfo) = self.res_read();
let (_, w_rqinfo) = self.res_write();
let r_keys = r_rqinfo.resource_keys();
let w_keys = w_rqinfo.resource_keys();
for i in 0..w_keys.len() {
for j in i + 1..w_keys.len() {
if w_keys[i] == w_keys[j] {
let reason = debug_format!(
"duplicate resource query `{:?}` in request `{}`",
w_keys[i],
self.name(),
);
return Err(reason);
}
}
for r_key in r_keys.iter() {
if &w_keys[i] == r_key {
let reason = debug_format!(
"duplicate resource query `{:?}` in request `{}`",
w_keys[i],
self.name(),
);
return Err(reason);
}
}
}
Ok(())
}
}
impl Request for () {
type Read = ();
type Write = ();
type ResRead = ();
type ResWrite = ();
type EntWrite = ();
}
#[derive(Debug)]
pub struct SystemBuffer {
pub(crate) read: Box<[SelectedRaw]>,
pub(crate) write: Box<[SelectedRaw]>,
pub(crate) res_read: Vec<Borrowed<ManagedConstPtr<u8>>>,
pub(crate) res_write: Vec<Borrowed<ManagedMutPtr<u8>>>,
pub(crate) ent_write: Box<[FilteredRaw]>,
}
unsafe impl Send for SystemBuffer {}
impl SystemBuffer {
pub(crate) fn new() -> Self {
Self {
read: [].into(),
write: [].into(),
res_read: Vec::new(),
res_write: Vec::new(),
ent_write: [].into(),
}
}
pub(crate) fn clear(&mut self) {
#[cfg(feature = "check")]
self.clear_force();
}
pub(crate) fn clear_force(&mut self) {
for read in self.read.iter_mut() {
read.clear();
}
for write in self.write.iter_mut() {
write.clear();
}
self.res_read.clear();
self.res_write.clear();
for ent_write in self.ent_write.iter_mut() {
ent_write.clear();
}
}
}
impl Default for SystemBuffer {
fn default() -> Self {
Self::new()
}
}
pub struct Response<'buf, Req> {
buf: &'buf mut SystemBuffer,
_marker: PhantomData<Req>,
}
impl<'buf, Req: Request> Response<'buf, Req> {
pub(crate) fn new(buf: &'buf mut SystemBuffer) -> Self {
Self {
buf,
_marker: PhantomData,
}
}
pub fn all(&mut self) -> ResponseAll<'_, Req> {
ResponseAll {
read: <Req::Read as Query>::convert(&mut self.buf.read),
write: <Req::Write as QueryMut>::convert(&mut self.buf.write),
res_read: <Req::ResRead as ResQuery>::convert(&mut self.buf.res_read),
res_write: <Req::ResWrite as ResQueryMut>::convert(&mut self.buf.res_write),
ent_write: <Req::EntWrite as EntQueryMut>::convert(&mut self.buf.ent_write),
}
}
pub fn read(&mut self) -> <Req::Read as Query>::Output<'_> {
<Req::Read as Query>::convert(&mut self.buf.read)
}
pub fn write(&mut self) -> <Req::Write as QueryMut>::Output<'_> {
<Req::Write as QueryMut>::convert(&mut self.buf.write)
}
pub fn res_read(&mut self) -> <Req::ResRead as ResQuery>::Output<'_> {
<Req::ResRead as ResQuery>::convert(&mut self.buf.res_read)
}
pub fn res_write(&mut self) -> <Req::ResWrite as ResQueryMut>::Output<'_> {
<Req::ResWrite as ResQueryMut>::convert(&mut self.buf.res_write)
}
pub fn ent_write(&mut self) -> <Req::EntWrite as EntQueryMut>::Output<'_> {
<Req::EntWrite as EntQueryMut>::convert(&mut self.buf.ent_write)
}
}
impl<Req> Drop for Response<'_, Req> {
fn drop(&mut self) {
self.buf.clear();
}
}
pub struct ResponseAll<'a, Req: Request> {
pub read: <Req::Read as Query>::Output<'a>,
pub write: <Req::Write as QueryMut>::Output<'a>,
pub res_read: <Req::ResRead as ResQuery>::Output<'a>,
pub res_write: <Req::ResWrite as ResQueryMut>::Output<'a>,
pub ent_write: <Req::EntWrite as EntQueryMut>::Output<'a>,
}