#[cfg(feature = "flecs_safety_locks")]
use crate::core::QueryTuple;
use crate::core::{IdOperations, IdView};
use super::WorldRef;
use flecs_ecs::sys;
const WRITE_FLAG: u16 = 1 << 15;
const READ_MASK: u16 = WRITE_FLAG - 1;
type ComponentOrPairId = u64;
type TableId = u64;
type ComponentOrPairIdAndTableId = u128;
pub(crate) fn combone_ids(id: ComponentOrPairId, table_id: TableId) -> ComponentOrPairIdAndTableId {
((id as u128) << 64) | (table_id as u128)
}
#[cfg(feature = "flecs_safety_locks")]
pub(super) const INCREMENT: bool = true;
#[cfg(feature = "flecs_safety_locks")]
pub(super) const DECREMENT: bool = false;
#[cfg(feature = "flecs_safety_locks")]
#[inline(always)]
fn lock_table<const INCREMENT: bool, const READONLY: bool, const MULTITHREADED: bool>(
world: &WorldRef,
table: *mut sys::ecs_table_t,
col: i16,
stage: i32,
) {
if READONLY {
if INCREMENT {
get_table_column_lock_read_begin::<MULTITHREADED>(world, table, col, stage);
} else {
table_column_lock_read_end::<MULTITHREADED>(table, col, stage);
}
} else if INCREMENT {
get_table_column_lock_write_begin::<MULTITHREADED>(world, table, col, stage);
} else {
table_column_lock_write_end::<MULTITHREADED>(table, col, stage);
}
}
#[cfg(feature = "flecs_safety_locks")]
#[inline(always)]
fn lock_sparse<const INCREMENT: bool, const READONLY: bool, const MULTITHREADED: bool>(
world: &WorldRef,
idr: *mut sys::ecs_component_record_t,
) {
if READONLY {
if INCREMENT {
sparse_id_record_lock_read_begin::<MULTITHREADED>(world, idr);
} else {
sparse_id_record_lock_read_end::<MULTITHREADED>(idr);
}
} else if INCREMENT {
sparse_id_record_lock_write_begin::<MULTITHREADED>(world, idr);
} else {
sparse_id_record_lock_write_end::<MULTITHREADED>(idr);
}
}
#[inline]
#[cfg(feature = "flecs_safety_locks")]
pub(crate) fn do_read_write_locks<
const INCREMENT: bool,
const ANY_SPARSE_TERMS: bool,
T: QueryTuple,
>(
world: &WorldRef,
table_records: &[super::TableColumnSafety],
) {
let multithreaded = world.is_currently_multithreaded();
if multithreaded {
let stage = world.stage_id();
__internal_do_read_write_locks::<INCREMENT, true, ANY_SPARSE_TERMS, T>(
world,
stage,
table_records,
);
} else {
__internal_do_read_write_locks::<INCREMENT, false, ANY_SPARSE_TERMS, T>(
world,
0,
table_records,
);
}
}
#[inline(always)]
fn __internal_do_read_write_locks<
const INCREMENT: bool,
const MULTITHREADED: bool,
const ANY_SPARSE_TERMS: bool,
T: QueryTuple,
>(
world: &WorldRef<'_>,
stage: i32,
table_records: &[super::TableColumnSafety],
) {
let count_immutable: usize = const { T::COUNT_IMMUTABLE };
let start_index_mutable: usize = const { T::COUNT_IMMUTABLE };
let start_index_optional_immutable: usize = const { T::COUNT_IMMUTABLE + T::COUNT_MUTABLE };
let start_index_optional_mutable: usize =
const { T::COUNT_IMMUTABLE + T::COUNT_MUTABLE + T::COUNT_OPTIONAL_IMMUTABLE };
let end_index_mutable: usize = const { T::COUNT_IMMUTABLE + T::COUNT_MUTABLE };
let end_index_optional_immutable: usize =
const { T::COUNT_IMMUTABLE + T::COUNT_MUTABLE + T::COUNT_OPTIONAL_IMMUTABLE };
let end_index_optional_mutable: usize = const {
T::COUNT_IMMUTABLE
+ T::COUNT_MUTABLE
+ T::COUNT_OPTIONAL_IMMUTABLE
+ T::COUNT_OPTIONAL_MUTABLE
};
unsafe {
for i in 0..count_immutable {
let info = table_records.get_unchecked(i);
let tr = info.table_record;
if ANY_SPARSE_TERMS && info.component_id != 0 {
let idr = if tr.is_null() {
sys::flecs_components_get(world.raw_world.as_ptr(), info.component_id)
} else {
(&*tr).hdr.cr
};
lock_sparse::<INCREMENT, true, MULTITHREADED>(world, idr);
continue;
}
let tr = &*tr;
let col = tr.column;
let table = tr.hdr.table;
lock_table::<INCREMENT, true, MULTITHREADED>(world, table, col, stage);
}
for i in start_index_mutable..end_index_mutable {
let info = table_records.get_unchecked(i);
let tr = info.table_record;
if ANY_SPARSE_TERMS && info.component_id != 0 {
let idr = if tr.is_null() {
sys::flecs_components_get(world.raw_world.as_ptr(), info.component_id)
} else {
(&*tr).hdr.cr
};
lock_sparse::<INCREMENT, false, MULTITHREADED>(world, idr);
continue;
}
let tr = &*tr;
let col = tr.column;
let table = tr.hdr.table;
lock_table::<INCREMENT, false, MULTITHREADED>(world, table, col, stage);
}
for i in start_index_optional_immutable..end_index_optional_immutable {
let info = table_records.get_unchecked(i);
let tr = info.table_record;
if !ANY_SPARSE_TERMS && tr.is_null() {
continue;
}
if ANY_SPARSE_TERMS {
let is_comp_id_set = info.component_id != 0;
if is_comp_id_set {
let idr = if tr.is_null() {
sys::flecs_components_get(world.raw_world.as_ptr(), info.component_id)
} else {
(&*tr).hdr.cr
};
lock_sparse::<INCREMENT, true, MULTITHREADED>(world, idr);
continue;
} else if tr.is_null() {
continue;
}
}
let tr = &*tr;
let col = tr.column;
let table = tr.hdr.table;
lock_table::<INCREMENT, true, MULTITHREADED>(world, table, col, stage);
}
for i in start_index_optional_mutable..end_index_optional_mutable {
let info = table_records.get_unchecked(i);
let tr = info.table_record;
if !ANY_SPARSE_TERMS && tr.is_null() {
continue;
}
if ANY_SPARSE_TERMS {
let is_comp_id_set = info.component_id != 0;
if is_comp_id_set {
let idr = if tr.is_null() {
sys::flecs_components_get(world.raw_world.as_ptr(), info.component_id)
} else {
(&*tr).hdr.cr
};
lock_sparse::<INCREMENT, false, MULTITHREADED>(world, idr);
continue;
} else if tr.is_null() {
continue;
}
}
let tr = &*tr;
let col = tr.column;
let table = tr.hdr.table;
lock_table::<INCREMENT, false, MULTITHREADED>(world, table, col, stage);
}
}
}
#[inline(always)]
fn component_id_from_table_column(table: *mut sys::ecs_table_t, column: i16) -> u64 {
unsafe {
*(*sys::ecs_table_get_type(table))
.array
.add(sys::ecs_table_column_to_type_index(table, column as i32) as usize)
}
}
#[inline(always)]
pub(crate) fn sparse_id_record_lock_read_begin<const MULTITHREADED: bool>(
world: &WorldRef,
idr: *mut sys::ecs_component_record_t,
) {
let val = if MULTITHREADED {
unsafe { sys::flecs_sparse_id_record_lock_read_begin_multithreaded(idr) }
} else {
unsafe { sys::flecs_sparse_id_record_lock_read_begin(idr) }
};
if val {
panic!(
"Cannot increment read: write already set for component: {}",
{
let id = IdView::new_from_id(world, unsafe { sys::flecs_component_get_id(idr) });
if id.is_pair() {
format!(
"({}, {})",
world.entity_from_id(id.first_id()),
world.entity_from_id(id.second_id())
)
} else {
format!("{}", id.entity_view())
}
},
);
}
}
#[inline(always)]
pub(crate) fn sparse_id_record_lock_read_end<const MULTITHREADED: bool>(
idr: *mut sys::ecs_component_record_t,
) {
if MULTITHREADED {
unsafe {
sys::flecs_sparse_id_record_lock_read_end_multithreaded(idr);
}
} else {
unsafe {
sys::flecs_sparse_id_record_lock_read_end(idr);
}
}
}
#[inline(always)]
pub(crate) fn sparse_id_record_lock_write_begin<const MULTITHREADED: bool>(
world: &WorldRef,
idr: *mut sys::ecs_component_record_t,
) {
let val = if MULTITHREADED {
unsafe { sys::flecs_sparse_id_record_lock_write_begin_multithreaded(idr) }
} else {
unsafe { sys::flecs_sparse_id_record_lock_write_begin(idr) }
};
unsafe {
if val {
panic!(
"Cannot set write: reads already present or write already set for component: {}",
{
let id = IdView::new_from_id(world, sys::flecs_component_get_id(idr));
if id.is_pair() {
format!(
"({}, {})",
world.entity_from_id(id.first_id()),
world.entity_from_id(id.second_id())
)
} else {
format!("{}", id.entity_view())
}
},
);
}
}
}
#[inline(always)]
pub(crate) fn sparse_id_record_lock_write_end<const MULTITHREADED: bool>(
idr: *mut sys::ecs_component_record_t,
) {
if MULTITHREADED {
unsafe {
sys::flecs_sparse_id_record_lock_write_end_multithreaded(idr);
}
} else {
unsafe {
sys::flecs_sparse_id_record_lock_write_end(idr);
}
}
}
#[inline(always)]
pub(crate) fn get_table_column_lock_read_begin<const MULTITHREADED: bool>(
world: &WorldRef,
table: *mut sys::ecs_table_t,
column: i16,
_stage_id: i32,
) {
let val = if MULTITHREADED {
unsafe { sys::flecs_table_column_lock_read_begin_multithreaded(table, column, _stage_id) }
} else {
unsafe { sys::flecs_table_column_lock_read_begin(table, column) }
};
if val {
panic!(
"Cannot increment read: write already set for component: {}",
{
let id = IdView::new_from_id(world, component_id_from_table_column(table, column));
if id.is_pair() {
format!(
"({}, {})",
world.entity_from_id(id.first_id()),
world.entity_from_id(id.second_id())
)
} else {
format!("{}", id.entity_view())
}
},
);
}
}
#[inline(always)]
pub(crate) fn table_column_lock_read_begin<const MULTITHREADED: bool>(
_world: &WorldRef,
table: *mut sys::ecs_table_t,
column: i16,
_stage_id: i32,
) -> bool {
if MULTITHREADED {
unsafe { sys::flecs_table_column_lock_read_begin_multithreaded(table, column, _stage_id) }
} else {
unsafe { sys::flecs_table_column_lock_read_begin(table, column) }
}
}
#[inline(always)]
pub(crate) fn table_column_lock_read_end<const MULTITHREADED: bool>(
table: *mut sys::ecs_table_t,
column: i16,
_stage_id: i32,
) {
if MULTITHREADED {
unsafe {
sys::flecs_table_column_lock_read_end_multithreaded(table, column, _stage_id);
}
} else {
unsafe {
sys::flecs_table_column_lock_read_end(table, column);
}
}
}
#[inline(always)]
pub(crate) fn table_column_lock_write_begin<const MULTITHREADED: bool>(
_world: &WorldRef,
table: *mut sys::ecs_table_t,
column: i16,
_stage_id: i32,
) -> bool {
if MULTITHREADED {
unsafe { sys::flecs_table_column_lock_write_begin_multithreaded(table, column, _stage_id) }
} else {
unsafe { sys::flecs_table_column_lock_write_begin(table, column) }
}
}
pub(crate) fn get_table_column_lock_write_begin<const MULTITHREADED: bool>(
world: &WorldRef,
table: *mut sys::ecs_table_t,
column: i16,
_stage_id: i32,
) {
let val = if MULTITHREADED {
unsafe { sys::flecs_table_column_lock_write_begin_multithreaded(table, column, _stage_id) }
} else {
unsafe { sys::flecs_table_column_lock_write_begin(table, column) }
};
if val {
panic!(
"Cannot set write: reads already present or write already set for component: {}",
{
let id = IdView::new_from_id(world, component_id_from_table_column(table, column));
if id.is_pair() {
format!(
"({}, {})",
world.entity_from_id(id.first_id()),
world.entity_from_id(id.second_id())
)
} else {
format!("{}", id.entity_view())
}
},
);
}
}
#[inline(always)]
pub(crate) fn table_column_lock_write_end<const MULTITHREADED: bool>(
table: *mut sys::ecs_table_t,
column: i16,
_stage_id: i32,
) {
if MULTITHREADED {
unsafe { sys::flecs_table_column_lock_write_end_multithreaded(table, column, _stage_id) }
} else {
unsafe { sys::flecs_table_column_lock_write_end(table, column) }
};
}