Skip to content

Commit

Permalink
Merge pull request #8 from Indra-db/rework_iterable
Browse files Browse the repository at this point in the history
Rework iterable to allow Immutable components refs + placed in any order in the tuple list (same for Optional Components)
  • Loading branch information
Indra-db authored Mar 6, 2024
2 parents 0c1f2bd + 90f46c4 commit 4362ac3
Show file tree
Hide file tree
Showing 19 changed files with 612 additions and 1,397 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,13 @@ This library has not been advertized nor published yet to crates.io for that rea
- [x] create filter builder
- [x] add support for optional components
- [x] add support for parent / instancing matching
- [ ] const only components
- [x] immutable only components
- [x] query
- [x] create query
- [x] create query builder
- [x] add support for optional components
- [x] add support for parent / instancing matching
- [ ] const only components
- [x] immutable only components
```

#### non-core
Expand Down
2 changes: 1 addition & 1 deletion flecs_ecs/benches/query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ fn query_each_benchmark(c: &mut Criterion) {
}
}

let mut query = Query::<(Pos, Vel)>::new(&world);
let mut query = Query::<(&mut Pos, &Vel)>::new(&world);

c.bench_function("query_each", |b| {
b.iter(|| {
Expand Down
2 changes: 1 addition & 1 deletion flecs_ecs/examples/entity_basics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ fn main() {
alice.remove::<Walking>();

// Iterate all entities with position
world.each_entity::<(Position,)>(|entity, pos| {
world.each_entity::<(&Position,)>(|entity, pos| {
println!("{} has {:?}", entity.get_name(), pos);
});

Expand Down
2 changes: 1 addition & 1 deletion flecs_ecs/examples/entity_prefab.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ fn main() {
println!("ImpulseSpeed: {}", impulse_speed.unwrap().value);

// Prefab components can be iterated just like regular components:
world.each_entity::<(ImpulseSpeed, Position)>(|entity, (impulse_speed, position)| {
world.each_entity::<(&ImpulseSpeed, &mut Position)>(|entity, (impulse_speed, position)| {
position.x += impulse_speed.value;
println!("Entity {}: {:?}", entity.get_name(), position);
});
Expand Down
2 changes: 1 addition & 1 deletion flecs_ecs/examples/hello_world.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ fn main() {

// Register system
let _sys = world
.system_builder::<(Position, Velocity)>()
.system_builder::<(&mut Position, &Velocity)>()
// .on_each_entity if you want the entity to be added in the parameter list
.on_each(|(pos, vel)| {
pos.x += vel.x;
Expand Down
2 changes: 1 addition & 1 deletion flecs_ecs/examples/query_basics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ fn main() {

// Create a query for Position, Velocity. Queries are the fastest way to
// iterate entities as they cache results.
let mut query = world.query::<(Position, Velocity)>();
let mut query = world.query::<(&mut Position, &Velocity)>();

// Create a few test entities for a Position, Velocity query
world
Expand Down
3 changes: 3 additions & 0 deletions flecs_ecs/src/core/c_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -392,6 +392,7 @@ fn get_ecs_poly_data() -> ComponentData {
impl ComponentType<Struct> for EcsComponent {}

impl CachedComponentData for EcsComponent {
type UnderlyingType = EcsComponent;
fn register_explicit(_world: *mut WorldT) {
//this is already registered as FLECS_IDEcsComponentID_
Self::__get_once_lock_data().get_or_init(get_ecs_component_data);
Expand Down Expand Up @@ -471,6 +472,7 @@ impl Default for Poly {
impl ComponentType<Struct> for Poly {}

impl CachedComponentData for Poly {
type UnderlyingType = Poly;
fn register_explicit(_world: *mut WorldT) {
//this is already registered as FLECS_IDEcsComponentID_
Self::__get_once_lock_data().get_or_init(get_ecs_poly_data);
Expand Down Expand Up @@ -778,6 +780,7 @@ impl Default for TickSource {
}

impl CachedComponentData for TickSource {
type UnderlyingType = TickSource;
fn register_explicit(world: *mut WorldT) {
try_register_struct_component::<Self>(world);
}
Expand Down
6 changes: 3 additions & 3 deletions flecs_ecs/src/core/component.rs
Original file line number Diff line number Diff line change
Expand Up @@ -123,20 +123,20 @@ impl UntypedComponent {}

/// Component class.
/// Class used to register components and component metadata.
pub struct Component<T: CachedComponentData + Default> {
pub struct Component<T: CachedComponentData> {
pub base: UntypedComponent,
_marker: PhantomData<T>,
}

impl<T: CachedComponentData + Default> Deref for Component<T> {
impl<T: CachedComponentData> Deref for Component<T> {
type Target = UntypedComponent;

fn deref(&self) -> &Self::Target {
&self.base
}
}

impl<T: CachedComponentData + Default> Component<T> {
impl<T: CachedComponentData> Component<T> {
/// Create a new component.
///
/// # Arguments
Expand Down
16 changes: 10 additions & 6 deletions flecs_ecs/src/core/component_registration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,9 @@ pub trait ComponentType<T: ECSComponentType>: CachedComponentData {}
/// If the world doesn't, this implies the component was registered by a different world.
/// In such a case, the component is registered with the present world using the pre-existing ID.
/// If the ID is already known, the trait takes care of the component registration and checks for consistency in the input.
pub trait CachedComponentData: Clone + Default {
pub trait CachedComponentData: Sized {
type UnderlyingType: CachedComponentData + Default + Clone;

/// attempts to register the component with the world. If it's already registered, it does nothing.
fn register_explicit(world: *mut WorldT);

Expand All @@ -79,7 +81,7 @@ pub trait CachedComponentData: Clone + Default {
#[allow(clippy::not_unsafe_ptr_arg_deref)]
fn is_registered_with_world(world: *mut WorldT) -> bool {
if Self::is_registered() {
unsafe { is_component_registered_with_world::<Self>(world) }
unsafe { is_component_registered_with_world::<Self::UnderlyingType>(world) }
} else {
false
}
Expand Down Expand Up @@ -314,7 +316,7 @@ fn register_componment_data_explicit<T>(
is_comp_pre_registered: bool,
) -> bool
where
T: CachedComponentData + Clone + Default,
T: CachedComponentData,
{
let mut component_data: ComponentData = Default::default();
if is_comp_pre_registered {
Expand Down Expand Up @@ -420,7 +422,7 @@ pub(crate) fn register_entity_w_component_explicit<T>(
id: EntityT,
) -> EntityT
where
T: CachedComponentData + Clone + Default,
T: CachedComponentData,
{
let is_comp_pre_registered = T::is_registered();
let mut component_data: ComponentData = Default::default();
Expand Down Expand Up @@ -530,7 +532,7 @@ pub(crate) fn register_component_data<T>(
is_comp_pre_registered_with_world: bool,
) -> bool
where
T: CachedComponentData + Clone + Default,
T: CachedComponentData,
{
let mut has_registered = false;
//this is safe because we checked if the component is pre-registered
Expand Down Expand Up @@ -559,7 +561,9 @@ where
// Register lifecycle callbacks, but only if the component has a
// size. Components that don't have a size are tags, and tags don't
// require construction/destruction/copy/move's.
register_lifecycle_actions::<T>(world, unsafe { T::get_id_unchecked() });
register_lifecycle_actions::<T::UnderlyingType>(world, unsafe {
T::get_id_unchecked()
});
}

if prev_with != 0 {
Expand Down
39 changes: 26 additions & 13 deletions flecs_ecs/src/core/entity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1625,15 +1625,20 @@ impl Entity {
///
/// * C++ API: `entity::get_mut`
#[doc(alias = "entity::get_mut")]
pub fn get_mut<T: CachedComponentData + ComponentType<Struct>>(&self) -> Option<&mut T> {
pub fn get_mut<T: CachedComponentData + ComponentType<Struct>>(
&self,
) -> Option<&mut T::UnderlyingType> {
let component_id = T::get_id(self.world);
ecs_assert!(
T::get_size(self.world) != 0,
FlecsErrorCode::InvalidParameter,
"invalid type: {}",
T::get_symbol_name()
);
unsafe { (ecs_get_mut_id(self.world, self.raw_id, component_id) as *mut T).as_mut() }
unsafe {
(ecs_get_mut_id(self.world, self.raw_id, component_id) as *mut T::UnderlyingType)
.as_mut()
}
}

/// Gets mut component unchecked
Expand Down Expand Up @@ -1661,15 +1666,15 @@ impl Entity {
#[doc(alias = "entity::get_mut")]
pub unsafe fn get_unchecked_mut<T: CachedComponentData + ComponentType<Struct>>(
&mut self,
) -> &mut T {
) -> &mut T::UnderlyingType {
let component_id = T::get_id(self.world);
ecs_assert!(
T::get_size(self.world) != 0,
FlecsErrorCode::InvalidParameter,
"invalid type: {}",
T::get_symbol_name()
);
let ptr = ecs_get_mut_id(self.world, self.raw_id, component_id) as *mut T;
let ptr = ecs_get_mut_id(self.world, self.raw_id, component_id) as *mut T::UnderlyingType;
ecs_assert!(
!ptr.is_null(),
FlecsErrorCode::InternalError,
Expand All @@ -1695,17 +1700,23 @@ impl Entity {
///
/// * C++ API: `entity::get_mut`
#[doc(alias = "entity::get_mut")]
pub fn get_enum_mut<T: CachedComponentData + ComponentType<Enum>>(&self) -> Option<&mut T> {
pub fn get_enum_mut<T: CachedComponentData + ComponentType<Enum>>(
&self,
) -> Option<&mut T::UnderlyingType> {
let component_id: IdT = T::get_id(self.world);
let target: IdT = unsafe { ecs_get_target(self.world, self.raw_id, component_id, 0) };

if target == 0 {
// if there is no matching pair for (r,*), try just r
unsafe { (ecs_get_mut_id(self.world, self.raw_id, component_id) as *mut T).as_mut() }
unsafe {
(ecs_get_mut_id(self.world, self.raw_id, component_id) as *mut T::UnderlyingType)
.as_mut()
}
} else {
// get constant value from constant entity
let constant_value =
unsafe { ecs_get_mut_id(self.world, target, component_id) as *mut T };
let constant_value = unsafe {
ecs_get_mut_id(self.world, target, component_id) as *mut T::UnderlyingType
};

ecs_assert!(
!constant_value.is_null(),
Expand Down Expand Up @@ -1738,13 +1749,14 @@ impl Entity {
#[doc(alias = "entity::get_mut")]
pub unsafe fn get_enum_unchecked_mut<T: CachedComponentData + ComponentType<Enum>>(
&mut self,
) -> &mut T {
) -> &mut T::UnderlyingType {
let component_id: IdT = T::get_id(self.world);
let target: IdT = ecs_get_target(self.world, self.raw_id, component_id, 0);

if target == 0 {
// if there is no matching pair for (r,*), try just r
let ptr = ecs_get_mut_id(self.world, self.raw_id, component_id) as *mut T;
let ptr =
ecs_get_mut_id(self.world, self.raw_id, component_id) as *mut T::UnderlyingType;
ecs_assert!(
!ptr.is_null(),
FlecsErrorCode::InternalError,
Expand All @@ -1755,7 +1767,8 @@ impl Entity {
&mut *ptr
} else {
// get constant value from constant entity
let constant_value = ecs_get_mut_id(self.world, target, component_id) as *mut T;
let constant_value =
ecs_get_mut_id(self.world, target, component_id) as *mut T::UnderlyingType;
ecs_assert!(
!constant_value.is_null(),
FlecsErrorCode::InternalError,
Expand Down Expand Up @@ -2026,8 +2039,8 @@ impl Entity {
///
/// * C++ API: `entity::get_ref`
#[doc(alias = "entity::get_ref")]
pub fn get_ref_component<T: CachedComponentData>(&self) -> Ref<T> {
Ref::<T>::new(self.world, self.raw_id, T::get_id(self.world))
pub fn get_ref_component<T: CachedComponentData>(&self) -> Ref<T::UnderlyingType> {
Ref::<T::UnderlyingType>::new(self.world, self.raw_id, T::get_id(self.world))
}

/// Get a reference to the first component of pair
Expand Down
34 changes: 24 additions & 10 deletions flecs_ecs/src/core/entity_view.rs
Original file line number Diff line number Diff line change
Expand Up @@ -635,9 +635,13 @@ impl EntityView {
///
/// * C++ API: `entity_view::get`
#[doc(alias = "entity_view::get")]
pub fn get<T: CachedComponentData + ComponentType<Struct>>(&self) -> Option<&T> {
pub fn get<T: CachedComponentData + ComponentType<Struct>>(
&self,
) -> Option<&T::UnderlyingType> {
let component_id = T::get_id(self.world);
unsafe { (ecs_get_id(self.world, self.raw_id, component_id) as *const T).as_ref() }
unsafe {
(ecs_get_id(self.world, self.raw_id, component_id) as *const T::UnderlyingType).as_ref()
}
}

/// Get (struct) Component from entity unchecked
Expand All @@ -658,9 +662,11 @@ impl EntityView {
///
/// * C++ API: `entity_view::get`
#[doc(alias = "entity_view::get")]
pub unsafe fn get_unchecked<T: CachedComponentData + ComponentType<Struct>>(&self) -> &T {
pub unsafe fn get_unchecked<T: CachedComponentData + ComponentType<Struct>>(
&self,
) -> &T::UnderlyingType {
let component_id = T::get_id(self.world);
let ptr = ecs_get_id(self.world, self.raw_id, component_id) as *const T;
let ptr = ecs_get_id(self.world, self.raw_id, component_id) as *const T::UnderlyingType;
ecs_assert!(
!ptr.is_null(),
FlecsErrorCode::InternalError,
Expand All @@ -685,17 +691,22 @@ impl EntityView {
///
/// * C++ API: `entity_view::get`
#[doc(alias = "entity_view::get")]
pub fn get_enum<T: CachedComponentData + ComponentType<Enum>>(&self) -> Option<&T> {
pub fn get_enum<T: CachedComponentData + ComponentType<Enum>>(
&self,
) -> Option<&T::UnderlyingType> {
let component_id: IdT = T::get_id(self.world);
let target: IdT = unsafe { ecs_get_target(self.world, self.raw_id, component_id, 0) };

if target == 0 {
// if there is no matching pair for (r,*), try just r
unsafe { (ecs_get_id(self.world, self.raw_id, component_id) as *const T).as_ref() }
unsafe {
(ecs_get_id(self.world, self.raw_id, component_id) as *const T::UnderlyingType)
.as_ref()
}
} else {
// get constant value from constant entity
let constant_value =
unsafe { ecs_get_id(self.world, target, component_id) as *const T };
unsafe { ecs_get_id(self.world, target, component_id) as *const T::UnderlyingType };

ecs_assert!(
!constant_value.is_null(),
Expand Down Expand Up @@ -726,13 +737,15 @@ impl EntityView {
///
/// * C++ API: `entity_view::get`
#[doc(alias = "entity_view::get")]
pub unsafe fn get_enum_unchecked<T: CachedComponentData + ComponentType<Enum>>(&self) -> &T {
pub unsafe fn get_enum_unchecked<T: CachedComponentData + ComponentType<Enum>>(
&self,
) -> &T::UnderlyingType {
let component_id: IdT = T::get_id(self.world);
let target: IdT = ecs_get_target(self.world, self.raw_id, component_id, 0);

if target == 0 {
// if there is no matching pair for (r,*), try just r
let ptr = ecs_get_id(self.world, self.raw_id, component_id) as *const T;
let ptr = ecs_get_id(self.world, self.raw_id, component_id) as *const T::UnderlyingType;
ecs_assert!(
!ptr.is_null(),
FlecsErrorCode::InternalError,
Expand All @@ -742,7 +755,8 @@ impl EntityView {
&*ptr
} else {
// get constant value from constant entity
let constant_value = ecs_get_id(self.world, target, component_id) as *const T;
let constant_value =
ecs_get_id(self.world, target, component_id) as *const T::UnderlyingType;
ecs_assert!(
!constant_value.is_null(),
FlecsErrorCode::InternalError,
Expand Down
2 changes: 1 addition & 1 deletion flecs_ecs/src/core/iter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ impl<'a> Iter<'a> {
///
/// * C++ API: `iter::type`
#[doc(alias = "iter::type")]
pub fn get_type(&self) -> Archetype {
pub fn get_archetype(&self) -> Archetype {
unsafe { Archetype::new(self.iter.world, ecs_table_get_type(self.iter.table)) }
}

Expand Down
Loading

0 comments on commit 4362ac3

Please sign in to comment.