#[cfg(feature = "flecs_safety_locks")]
use super::iter::FieldError;
use crate::core::*;
use crate::sys;
use core::ffi::c_void;
use core::ops::Index;
use core::ops::IndexMut;
use core::ops::{Deref, DerefMut};
#[cfg(feature = "flecs_safety_locks")]
use core::ptr::NonNull;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct FieldIndex(pub(crate) usize);
impl FieldIndex {
#[inline(always)]
pub unsafe fn new(value: usize) -> Self {
Self(value)
}
}
impl From<usize> for FieldIndex {
#[inline(always)]
fn from(value: usize) -> Self {
Self(value)
}
}
impl From<FieldIndex> for usize {
#[inline(always)]
fn from(value: FieldIndex) -> Self {
value.0
}
}
pub struct Field<'a, T, const LOCK: bool> {
pub(crate) slice_components: &'a [T],
pub(crate) is_shared: bool,
#[cfg(feature = "flecs_safety_locks")]
pub(crate) table: NonNull<sys::ecs_table_t>,
#[cfg(feature = "flecs_safety_locks")]
pub(crate) stage_id: Option<i32>,
#[cfg(feature = "flecs_safety_locks")]
pub(crate) column_index: i16,
#[cfg(feature = "flecs_safety_locks")]
pub(crate) field_index: i8,
}
impl<T, const LOCK: bool> core::fmt::Debug for Field<'_, T, LOCK>
where
T: core::fmt::Debug,
{
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "{:?}", self.slice_components)
}
}
#[cfg(feature = "flecs_safety_locks")]
impl<T, const LOCK: bool> Drop for Field<'_, T, LOCK> {
fn drop(&mut self) {
if LOCK {
unsafe {
if let Some(stage_id) = self.stage_id {
table_column_lock_read_end::<true>(
self.table.as_mut(),
self.column_index,
stage_id,
);
} else {
table_column_lock_read_end::<false>(self.table.as_mut(), self.column_index, 0);
}
}
}
}
}
impl<'a, T> Field<'a, T, false> {
#[cfg(feature = "flecs_safety_locks")]
#[inline(always)]
#[expect(dead_code, reason = "possibly used in the future")]
pub(crate) fn new_lockless(
slice_components: &'a [T],
is_shared: bool,
stage_id: i32,
column_index: i16,
field_index: i8,
table: NonNull<sys::ecs_table_t>,
world: &WorldRef,
) -> Self {
let stage_id = if world.is_currently_multithreaded() {
Some(stage_id)
} else {
None
};
Self {
slice_components,
is_shared,
table,
field_index,
stage_id,
column_index,
}
}
#[inline(always)]
#[expect(dead_code, reason = "possibly used in the future")]
#[cfg(not(feature = "flecs_safety_locks"))]
pub(crate) fn new_lockless(slice_components: &'a [T], is_shared: bool) -> Self {
Self {
slice_components,
is_shared,
}
}
}
impl<'a, T, const LOCK: bool> Field<'a, T, LOCK> {
#[cfg(not(feature = "flecs_safety_locks"))]
#[inline(always)]
pub(crate) fn new(slice_components: &'a [T], is_shared: bool) -> Self {
Self {
slice_components,
is_shared,
}
}
#[doc(alias = "field::field")]
#[cfg(feature = "flecs_safety_locks")]
pub(crate) fn new<const MULTITHREADED: bool>(
slice_components: &'a [T],
is_shared: bool,
stage_id: i32,
column_index: i16,
field_index: i8,
table: NonNull<sys::ecs_table_t>,
world: &WorldRef,
) -> Self {
if LOCK {
get_table_column_lock_read_begin::<MULTITHREADED>(
world,
table.as_ptr(),
column_index,
stage_id,
);
}
let stage_id = if MULTITHREADED { Some(stage_id) } else { None };
Self {
slice_components,
is_shared,
table,
field_index,
stage_id,
column_index,
}
}
#[doc(alias = "field::field")]
#[cfg(feature = "flecs_safety_locks")]
pub(crate) fn new_result<const MULTITHREADED: bool>(
slice_components: &'a [T],
is_shared: bool,
stage_id: i32,
column_index: i16,
field_index: i8,
table: NonNull<sys::ecs_table_t>,
world: &WorldRef,
) -> Result<Self, FieldError> {
if LOCK
&& table_column_lock_read_begin::<MULTITHREADED>(
world,
table.as_ptr(),
column_index,
stage_id,
)
{
return Err(FieldError::Locked);
}
let stage_id = if MULTITHREADED { Some(stage_id) } else { None };
Ok(Self {
slice_components,
is_shared,
table,
field_index,
stage_id,
column_index,
})
}
#[cfg(feature = "flecs_safety_locks")]
pub fn table_id(&self) -> u64 {
unsafe { sys::flecs_table_id(self.table.as_ptr()) }
}
pub fn drop(self) {}
#[inline(always)]
pub fn is_shared(&self) -> bool {
self.is_shared
}
#[inline(always)]
#[allow(clippy::len_without_is_empty)]
pub fn len(&self) -> usize {
self.slice_components.len()
}
#[inline(always)]
pub fn get(&self, index: usize) -> Option<&T> {
self.slice_components.get(index)
}
pub fn as_slice(&self) -> &[T] {
self.slice_components
}
}
impl<'a, T, const LOCK: bool> Index<FieldIndex> for Field<'a, T, LOCK> {
type Output = T;
#[inline(always)]
fn index(&self, idx: FieldIndex) -> &'a Self::Output {
ecs_assert!(
!(self.is_shared && idx.0 > 0),
FlecsErrorCode::InvalidParameter,
"Field is shared, cannot index above index 0"
);
unsafe { self.slice_components.get_unchecked(idx.0) }
}
}
impl<'a, T, const LOCK: bool> Index<usize> for Field<'a, T, LOCK> {
type Output = T;
#[inline(always)]
fn index(&self, idx: usize) -> &Self::Output {
ecs_assert!(
!(self.is_shared && idx > 0),
FlecsErrorCode::InvalidParameter,
"Field is shared, cannot index above index 0"
);
&self.slice_components[idx]
}
}
pub struct FieldMut<'a, T, const LOCK: bool> {
pub(crate) slice_components: &'a mut [T],
pub(crate) is_shared: bool,
#[cfg(feature = "flecs_safety_locks")]
pub(crate) table: NonNull<sys::ecs_table_t>,
#[cfg(feature = "flecs_safety_locks")]
pub(crate) stage_id: Option<i32>,
#[cfg(feature = "flecs_safety_locks")]
pub(crate) column_index: i16,
#[cfg(feature = "flecs_safety_locks")]
pub(crate) field_index: i8,
}
impl<T, const LOCK: bool> core::fmt::Debug for FieldMut<'_, T, LOCK>
where
T: core::fmt::Debug,
{
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "{:?}", self.slice_components)
}
}
#[cfg(feature = "flecs_safety_locks")]
impl<T, const LOCK: bool> Drop for FieldMut<'_, T, LOCK> {
fn drop(&mut self) {
if LOCK {
if let Some(stage_id) = self.stage_id {
unsafe {
table_column_lock_write_end::<true>(
self.table.as_mut(),
self.column_index,
stage_id,
);
}
} else {
unsafe {
table_column_lock_write_end::<false>(self.table.as_mut(), self.column_index, 0);
}
}
}
}
}
impl<'a, T> FieldMut<'a, T, false> {
#[cfg(feature = "flecs_safety_locks")]
#[inline(always)]
#[expect(dead_code, reason = "possibly used in the future")]
pub(crate) fn new_lockless(
slice_components: &'a mut [T],
is_shared: bool,
stage_id: i32,
column_index: i16,
field_index: i8,
table: NonNull<sys::ecs_table_t>,
world: &WorldRef,
) -> Self {
let stage_id = if world.is_currently_multithreaded() {
Some(stage_id)
} else {
None
};
Self {
slice_components,
is_shared,
table,
field_index,
stage_id,
column_index,
}
}
#[expect(dead_code, reason = "possibly used in the future")]
#[cfg(not(feature = "flecs_safety_locks"))]
#[inline(always)]
pub(crate) fn new_lockless(slice_components: &'a mut [T], is_shared: bool) -> Self {
Self {
slice_components,
is_shared,
}
}
}
impl<'a, T, const LOCK: bool> FieldMut<'a, T, LOCK> {
#[inline(always)]
#[cfg(not(feature = "flecs_safety_locks"))]
pub fn new(slice_components: &'a mut [T], is_shared: bool) -> Self {
Self {
slice_components,
is_shared,
}
}
#[doc(alias = "field::field")]
#[cfg(feature = "flecs_safety_locks")]
pub(crate) fn new<const MULTITHREADED: bool>(
slice_components: &'a mut [T],
is_shared: bool,
stage_id: i32,
column_index: i16,
field_index: i8,
table: NonNull<sys::ecs_table_t>,
world: &WorldRef,
) -> Self {
if LOCK {
get_table_column_lock_write_begin::<MULTITHREADED>(
world,
table.as_ptr(),
column_index,
stage_id,
);
}
let stage_id = if MULTITHREADED { Some(stage_id) } else { None };
Self {
slice_components,
is_shared,
table,
field_index,
stage_id,
column_index,
}
}
#[doc(alias = "field::field")]
#[cfg(feature = "flecs_safety_locks")]
pub(crate) fn new_result<const MULTITHREADED: bool>(
slice_components: &'a mut [T],
is_shared: bool,
stage_id: i32,
column_index: i16,
field_index: i8,
table: NonNull<sys::ecs_table_t>,
world: &WorldRef,
) -> Result<Self, FieldError> {
if LOCK
&& table_column_lock_write_begin::<MULTITHREADED>(
world,
table.as_ptr(),
column_index,
stage_id,
)
{
return Err(FieldError::Locked);
}
let stage_id = if MULTITHREADED { Some(stage_id) } else { None };
Ok(Self {
slice_components,
is_shared,
table,
field_index,
stage_id,
column_index,
})
}
#[cfg(feature = "flecs_safety_locks")]
pub fn table_id(&self) -> u64 {
unsafe { flecs_ecs_sys::flecs_table_id(self.table.as_ptr()) }
}
pub fn drop(self) {}
#[inline(always)]
pub fn is_shared(&self) -> bool {
self.is_shared
}
#[inline(always)]
#[allow(clippy::len_without_is_empty)]
pub fn len(&self) -> usize {
self.slice_components.len()
}
#[inline(always)]
pub fn get(&self, index: usize) -> Option<&T> {
self.slice_components.get(index)
}
#[inline(always)]
pub fn get_mut(&mut self, index: usize) -> Option<&mut T> {
self.slice_components.get_mut(index)
}
pub fn as_slice(&self) -> &[T] {
self.slice_components
}
pub fn as_mut_slice(&mut self) -> &mut [T] {
self.slice_components
}
}
impl<'a, T, const LOCK: bool> Index<FieldIndex> for FieldMut<'a, T, LOCK> {
type Output = T;
#[inline(always)]
fn index(&self, idx: FieldIndex) -> &T {
ecs_assert!(
!(self.is_shared && idx.0 > 0),
FlecsErrorCode::InvalidParameter,
"Field is shared, cannot index above index 0"
);
unsafe { self.slice_components.get_unchecked(idx.0) }
}
}
impl<'a, T, const LOCK: bool> IndexMut<FieldIndex> for FieldMut<'a, T, LOCK> {
#[inline(always)]
fn index_mut(&mut self, idx: FieldIndex) -> &mut T {
ecs_assert!(
!(self.is_shared && idx.0 > 0),
FlecsErrorCode::InvalidParameter,
"Field is shared, cannot index above index 0"
);
unsafe { &mut *self.slice_components.get_unchecked_mut(idx.0) }
}
}
impl<'a, T, const LOCK: bool> Index<usize> for FieldMut<'a, T, LOCK> {
type Output = T;
#[inline(always)]
fn index(&self, idx: usize) -> &T {
ecs_assert!(
!(self.is_shared && idx > 0),
FlecsErrorCode::InvalidParameter,
"Field is shared, cannot index above index 0"
);
&self.slice_components[idx]
}
}
impl<'a, T, const LOCK: bool> IndexMut<usize> for FieldMut<'a, T, LOCK> {
#[inline(always)]
fn index_mut(&mut self, idx: usize) -> &mut T {
ecs_assert!(
!(self.is_shared && idx > 0),
FlecsErrorCode::InvalidParameter,
"Field is shared, cannot index above index 0"
);
&mut self.slice_components[idx]
}
}
pub struct FieldAt<'a, T> {
pub(crate) component: &'a T,
#[cfg(feature = "flecs_safety_locks")]
pub(crate) idr: NonNull<sys::ecs_component_record_t>,
#[cfg(feature = "flecs_safety_locks")]
is_multithreaded: bool,
}
impl<T> core::fmt::Debug for FieldAt<'_, T>
where
T: core::fmt::Debug,
{
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "{:?}", self.component)
}
}
#[cfg(feature = "flecs_safety_locks")]
impl<T> Drop for FieldAt<'_, T> {
fn drop(&mut self) {
if self.is_multithreaded {
unsafe {
sparse_id_record_lock_read_end::<true>(self.idr.as_mut());
}
} else {
unsafe {
sparse_id_record_lock_read_end::<false>(self.idr.as_mut());
}
}
}
}
impl<T: ComponentId> Deref for FieldAt<'_, T> {
type Target = T;
#[inline(always)]
fn deref(&self) -> &Self::Target {
self.component
}
}
impl<'a, T> FieldAt<'a, T> {
#[cfg(not(feature = "flecs_safety_locks"))]
pub(crate) fn new(component: &'a T) -> Self {
Self { component }
}
#[cfg(feature = "flecs_safety_locks")]
pub(crate) fn new(
component: &'a T,
world: &WorldRef,
mut idr: NonNull<sys::ecs_component_record_t>,
) -> Self {
let is_multithreaded = world.is_currently_multithreaded();
if is_multithreaded {
sparse_id_record_lock_read_begin::<true>(world, unsafe { idr.as_mut() });
} else {
sparse_id_record_lock_read_begin::<false>(world, unsafe { idr.as_mut() });
}
Self {
component,
idr,
is_multithreaded,
}
}
}
pub struct FieldAtMut<'a, T> {
pub(crate) component: &'a mut T,
#[cfg(feature = "flecs_safety_locks")]
pub(crate) idr: NonNull<sys::ecs_component_record_t>,
#[cfg(feature = "flecs_safety_locks")]
is_multithreaded: bool,
}
impl<T> core::fmt::Debug for FieldAtMut<'_, T>
where
T: core::fmt::Debug,
{
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "{:?}", self.component)
}
}
#[cfg(feature = "flecs_safety_locks")]
impl<T> Drop for FieldAtMut<'_, T> {
fn drop(&mut self) {
if self.is_multithreaded {
unsafe {
sparse_id_record_lock_write_end::<true>(self.idr.as_mut());
}
} else {
unsafe {
sparse_id_record_lock_write_end::<false>(self.idr.as_mut());
}
}
}
}
impl<T: ComponentId> Deref for FieldAtMut<'_, T> {
type Target = T;
#[inline(always)]
fn deref(&self) -> &Self::Target {
self.component
}
}
impl<T: ComponentId> DerefMut for FieldAtMut<'_, T> {
#[inline(always)]
fn deref_mut(&mut self) -> &mut Self::Target {
self.component
}
}
impl<'a, T> FieldAtMut<'a, T> {
#[cfg(not(feature = "flecs_safety_locks"))]
#[inline(always)]
pub(crate) fn new(component: &'a mut T) -> Self {
Self { component }
}
#[cfg(feature = "flecs_safety_locks")]
#[inline(always)]
pub(crate) fn new(
component: &'a mut T,
world: &WorldRef,
mut idr: NonNull<sys::ecs_component_record_t>,
) -> Self {
let is_multithreaded = world.is_currently_multithreaded();
if is_multithreaded {
sparse_id_record_lock_write_begin::<true>(world, unsafe { idr.as_mut() });
} else {
sparse_id_record_lock_write_begin::<false>(world, unsafe { idr.as_mut() });
}
Self {
component,
idr,
is_multithreaded,
}
}
}
pub struct FieldUntyped {
pub(crate) array: *const c_void,
pub(crate) size: usize,
pub(crate) count: usize,
pub(crate) is_shared: bool,
}
impl FieldUntyped {
#[inline(always)]
pub(crate) fn new(array: *const c_void, size: usize, count: usize, is_shared: bool) -> Self {
Self {
array,
size,
count,
is_shared,
}
}
#[inline(always)]
pub fn at(&self, index: usize) -> *const c_void {
ecs_assert!(
index < self.count,
FlecsErrorCode::OutOfRange,
"Index {} is out of range {}",
index,
self.count
);
ecs_assert!(
!self.is_shared || index == 0,
FlecsErrorCode::InvalidParameter,
"Column is shared, cannot index"
);
unsafe { self.array.add(index * self.size) }
}
}
pub struct FieldUntypedMut {
pub(crate) array: *mut c_void,
pub(crate) size: usize,
pub(crate) count: usize,
pub(crate) is_shared: bool,
}
impl FieldUntypedMut {
#[inline(always)]
pub(crate) fn new(array: *mut c_void, size: usize, count: usize, is_shared: bool) -> Self {
Self {
array,
size,
count,
is_shared,
}
}
#[inline(always)]
pub fn at(&self, index: usize) -> *const c_void {
ecs_assert!(
index < self.count,
FlecsErrorCode::OutOfRange,
"Index {} is out of range {}",
index,
self.count
);
ecs_assert!(
!self.is_shared || index == 0,
FlecsErrorCode::InvalidParameter,
"Column is shared, cannot index"
);
unsafe { self.array.add(index * self.size) }
}
#[inline(always)]
pub fn at_mut(&self, index: usize) -> *mut c_void {
ecs_assert!(
index < self.count,
FlecsErrorCode::OutOfRange,
"Index {} is out of range {}",
index,
self.count
);
ecs_assert!(
!self.is_shared,
FlecsErrorCode::InvalidParameter,
"Column is shared, cannot index"
);
unsafe { self.array.add(index * self.size) }
}
}
#[inline(always)]
pub(crate) fn flecs_field<T>(it: &sys::ecs_iter_t, index: i8) -> *mut T {
let _size = const { core::mem::size_of::<T>() };
const {
assert!(core::mem::size_of::<T>() != 0, "Size of T must not be zero");
}
let index_usize = index as usize;
ecs_assert!(
it.flags & sys::EcsIterIsValid != 0,
FlecsErrorCode::InvalidParameter,
"operation invalid before calling next()"
);
ecs_assert!(
index >= 0,
FlecsErrorCode::InvalidParameter,
"invalid field index {}",
index
);
ecs_assert!(
index < it.field_count,
FlecsErrorCode::InvalidParameter,
"field index {} out of bounds",
index
);
ecs_assert!(
unsafe { sys::ecs_field_size(it, index) } == _size
|| unsafe { sys::ecs_field_size(it, index) } == 0,
FlecsErrorCode::InvalidParameter,
"mismatching size for field {}",
index
);
let ptrs = it.ptrs;
let offset = it.offset;
if ptrs.is_null() || offset != 0 {
return ecs_field_fallback(it, index);
}
let p = unsafe { *ptrs.add(index_usize) };
if p.is_null() {
return ecs_field_fallback(it, index);
}
p as *mut T
}
#[inline(never)]
fn ecs_field_fallback<T>(it: &sys::ecs_iter_t, index: i8) -> *mut T {
let index_usize = index as usize;
let tr = unsafe { *it.trs.add(index_usize) };
if tr.is_null() {
return core::ptr::null_mut();
}
let tr = unsafe { &*tr };
#[cfg(any(debug_assertions, feature = "flecs_force_enable_ecs_asserts"))]
{
ecs_assert!(
(unsafe { sys::ecs_id_get_flags(it.real_world, sys::ecs_field_id(it, index)) }
& sys::EcsIdSparse)
== 0,
FlecsErrorCode::InvalidOperation,
"use ecs_field_at to access fields for sparse components"
);
}
let src = unsafe { *it.sources.add(index_usize) };
let (table, row) = if src == 0 {
(it.table, it.offset as usize)
} else {
let r = unsafe { &*sys::ecs_record_find(it.real_world, src) };
let row = ecs_record_to_row(r.row) as usize;
(r.table, row)
};
ecs_assert!(
!table.is_null(),
FlecsErrorCode::InternalError,
"table is null"
);
ecs_assert!(
tr.hdr.table == table,
FlecsErrorCode::InternalError,
"table mismatch in table record"
);
let column_index = tr.column;
ecs_assert!(
column_index != -1,
FlecsErrorCode::NotAComponent,
"only components can be fetched with fields"
);
ecs_assert!(
column_index >= 0,
FlecsErrorCode::InternalError,
"column index {} is negative",
column_index
);
ecs_assert!(
(column_index as i32) < unsafe { sys::ecs_table_column_count(table) },
FlecsErrorCode::InternalError,
"column index {} out of bounds for table with {} columns",
column_index,
unsafe { sys::ecs_table_column_count(table) }
);
ecs_assert!(
(row as i32) < unsafe { sys::ecs_table_count(table) }
|| (!it.query.is_null()
&& (unsafe { (*it.query).flags } & sys::EcsQueryMatchEmptyTables) != 0),
FlecsErrorCode::InternalError,
"row {} out of bounds for table with {} rows",
row,
unsafe { sys::ecs_table_count(table) }
);
unsafe { sys::ecs_table_get_column(table, column_index as i32, row as i32) as *mut T }
}
pub(crate) fn flecs_field_w_size(it: &sys::ecs_iter_t, _size: usize, index: i8) -> *mut c_void {
let index_usize = index as usize;
ecs_assert!(
it.flags & sys::EcsIterIsValid != 0,
FlecsErrorCode::InvalidParameter,
"operation invalid before calling next()"
);
ecs_assert!(
index >= 0,
FlecsErrorCode::InvalidParameter,
"invalid field index {}",
index
);
ecs_assert!(
index < it.field_count,
FlecsErrorCode::InvalidParameter,
"field index {} out of bounds",
index
);
ecs_assert!(
_size != 0,
FlecsErrorCode::InvalidParameter,
"size must not be zero for field {}",
index
);
ecs_assert!(
unsafe { sys::ecs_field_size(it, index) } == _size
|| unsafe { sys::ecs_field_size(it, index) } == 0,
FlecsErrorCode::InvalidParameter,
"mismatching size for field {}",
index
);
if !it.ptrs.is_null() && it.offset == 0 {
let ptr = unsafe { *it.ptrs.add(index_usize) };
if !ptr.is_null() {
#[cfg(any(debug_assertions, feature = "flecs_force_enable_ecs_asserts"))]
{
}
return ptr;
}
}
let tr = unsafe { *it.trs.add(index_usize) };
if tr.is_null() {
ecs_assert!(
!unsafe { sys::ecs_field_is_set(it, index) },
FlecsErrorCode::InternalError,
"field is set but no table record found"
);
return core::ptr::null_mut();
}
let tr = unsafe { &*tr };
#[cfg(any(debug_assertions, feature = "flecs_force_enable_ecs_asserts"))]
{
ecs_assert!(
(unsafe { sys::ecs_id_get_flags(it.world, sys::ecs_field_id(it, index)) }
& sys::EcsIdSparse)
== 0,
FlecsErrorCode::InvalidOperation,
"use ecs_field_at to access fields for sparse components"
);
}
let src = unsafe { *it.sources.add(index_usize) };
let (table, row) = if src == 0 {
(it.table, it.offset as usize)
} else {
let r = unsafe { &*sys::ecs_record_find(it.real_world, src) };
let row = ecs_record_to_row(r.row) as usize;
(r.table, row)
};
ecs_assert!(
!table.is_null(),
FlecsErrorCode::InternalError,
"table is null"
);
ecs_assert!(
tr.hdr.table == table,
FlecsErrorCode::InternalError,
"table mismatch in table record"
);
let column_index = tr.column;
ecs_assert!(
column_index != -1,
FlecsErrorCode::NotAComponent,
"only components can be fetched with fields"
);
ecs_assert!(
column_index >= 0,
FlecsErrorCode::InternalError,
"column index {} is negative",
column_index
);
ecs_assert!(
(column_index as i32) < unsafe { sys::ecs_table_column_count(table) },
FlecsErrorCode::InternalError,
"column index {} out of bounds for table with {} columns",
column_index,
unsafe { sys::ecs_table_column_count(table) }
);
ecs_assert!(
(row as i32) < unsafe { sys::ecs_table_count(table) }
|| (!it.query.is_null()
&& (unsafe { (*it.query).flags } & sys::EcsQueryMatchEmptyTables) != 0),
FlecsErrorCode::InternalError,
"row {} out of bounds for table with {} rows",
row,
unsafe { sys::ecs_table_count(table) }
);
unsafe { sys::ecs_table_get_column(table, column_index as i32, row as i32) }
}