Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rework iterable to allow Immutable components refs + placed in any order in the tuple list (same for Optional Components) #8

Merged
merged 4 commits into from
Mar 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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