Skip to content

Commit

Permalink
Getting rid of ViewHas<C> and making generic operations on Views work…
Browse files Browse the repository at this point in the history
… with just ArchetypeHas<C.
  • Loading branch information
recatek committed Jan 22, 2025
1 parent f90381e commit afda315
Show file tree
Hide file tree
Showing 4 changed files with 90 additions and 99 deletions.
50 changes: 15 additions & 35 deletions macros/src/generate/world.rs
Original file line number Diff line number Diff line change
Expand Up @@ -890,12 +890,22 @@ fn section_archetype(archetype_data: &DataArchetype) -> TokenStream {
}

#[inline(always)]
fn resolve_extract(components: &Self::Components) -> &#Component {
fn resolve_extract_view<'a>(view: &'a Self::View<'_>) -> &'a #Component {
&view.#component
}

#[inline(always)]
fn resolve_extract_view_mut<'a>(view: &'a mut Self::View<'_>) -> &'a mut #Component {
&mut view.#component
}

#[inline(always)]
fn resolve_extract_components(components: &Self::Components) -> &#Component {
&components.#component
}

#[inline(always)]
fn resolve_extract_mut(components: &mut Self::Components) -> &mut #Component {
fn resolve_extract_components_mut(components: &mut Self::Components) -> &mut #Component {
&mut components.#component
}
}
Expand All @@ -916,14 +926,14 @@ fn section_archetype(archetype_data: &DataArchetype) -> TokenStream {
where
Self::Archetype: ArchetypeHas<C>
{
<Self::Archetype as ArchetypeHas<C>>::resolve_extract(self)
<Self::Archetype as ArchetypeHas<C>>::resolve_extract_components(self)
}

fn get_mut<C>(&mut self) -> &mut C
where
Self::Archetype: ArchetypeHas<C>
{
<Self::Archetype as ArchetypeHas<C>>::resolve_extract_mut(self)
<Self::Archetype as ArchetypeHas<C>>::resolve_extract_components_mut(self)
}

fn into_tuple(self) -> Self::Tuple {
Expand Down Expand Up @@ -1000,45 +1010,15 @@ fn section_archetype(archetype_data: &DataArchetype) -> TokenStream {
)*
}

impl<'a> View for #ArchetypeView<'a> {
impl<'a> View<'a> for #ArchetypeView<'a> {
type Archetype = #Archetype;

#[inline(always)]
fn index(&self) -> usize {
self.index
}

#[inline(always)]
fn component<C>(&self) -> &C
where
Self: ViewHas<C>
{
<Self as ViewHas<C>>::resolve_component(self)
}

#[inline(always)]
fn component_mut<C>(&mut self) -> &mut C
where
Self: ViewHas<C>
{
<Self as ViewHas<C>>::resolve_component_mut(self)
}
}

#(
impl<'a> ViewHas<#Component> for #ArchetypeView<'a> {
#[inline(always)]
fn resolve_component(&self) -> &#Component {
self.#component
}

#[inline(always)]
fn resolve_component_mut(&mut self) -> &mut #Component {
self.#component
}
}
)*

impl<'a> #ViewN<'a, #Archetype, #(#Component),*> for #ArchetypeView<'a> {
#[inline(always)]
fn new(
Expand Down
4 changes: 2 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -794,7 +794,7 @@ pub mod prelude {
pub use traits::{World, WorldHas};
pub use traits::{Archetype, ArchetypeHas};
pub use traits::Components;
pub use traits::{View, ViewHas};
pub use traits::{View};
pub use traits::{Borrow, BorrowHas};
}

Expand Down Expand Up @@ -831,6 +831,6 @@ pub mod __internal {
pub use traits::{World, WorldHas};
pub use traits::{Archetype, ArchetypeHas};
pub use traits::Components;
pub use traits::{View, ViewHas};
pub use traits::{View};
pub use traits::{Borrow, BorrowHas};
}
79 changes: 17 additions & 62 deletions src/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -157,12 +157,12 @@ pub trait World: Sized {
/// }
/// ```
#[inline(always)]
fn view<A: Archetype, K: EntityKeyTyped<A>>(&mut self, entity: K) -> Option<A::Borrow<'_>>
fn view<A: Archetype, K: EntityKeyTyped<A>>(&mut self, entity: K) -> Option<A::View<'_>>
where
Self: WorldHas<A>,
A: ArchetypeCanResolve<K>,
{
<Self as WorldHas<A>>::resolve_archetype_mut(self).borrow(entity)
<Self as WorldHas<A>>::resolve_archetype_mut(self).view(entity)
}

/// Gets a [`Borrow`] for the given entity across archetypes in the full world.
Expand Down Expand Up @@ -341,7 +341,7 @@ where
Self: 'a;

/// The view type when accessing a single entity's components simultaneously.
type View<'a>: View
type View<'a>: View<'a, Archetype = Self>
where
Self: 'a;

Expand Down Expand Up @@ -772,9 +772,13 @@ pub trait ArchetypeHas<C>: Archetype {
#[doc(hidden)]
fn resolve_borrow_component_mut<'a>(borrow: &'a Self::Borrow<'a>) -> RefMut<'a, C>;
#[doc(hidden)]
fn resolve_extract(named: &Self::Components) -> &C;
fn resolve_extract_view<'a>(view: &'a Self::View<'_>) -> &'a C;
#[doc(hidden)]
fn resolve_extract_mut(named: &mut Self::Components) -> &mut C;
fn resolve_extract_view_mut<'a>(view: &'a mut Self::View<'_>) -> &'a mut C;
#[doc(hidden)]
fn resolve_extract_components(components: &Self::Components) -> &C;
#[doc(hidden)]
fn resolve_extract_components_mut(components: &mut Self::Components) -> &mut C;
}

pub trait Components {
Expand Down Expand Up @@ -807,80 +811,31 @@ pub trait Components {
// DEV NOTE: There's no point in trying to make a View/ViewMut split because each column is in
// a RefCell anyway, so you can't make non-mut references to them without borrowing, and Borrow
// already exists for that. Borrow also does it better, since it doesn't fully borrow each slice.
pub trait View {
type Archetype: Archetype;
pub trait View<'a> {
type Archetype: Archetype<View<'a> = Self> + 'a;

/// Returns the archetype dense index that this view refers to.
fn index(&self) -> usize;

/// Fetches the given component from this view.
#[inline(always)]
fn component<C>(&self) -> &C
fn component<'b, C>(&'b self) -> &'b C
where
Self: ViewHas<C>,
Self::Archetype: ArchetypeHas<C>
{
<Self as ViewHas<C>>::resolve_component(self)
<Self::Archetype as ArchetypeHas<C>>::resolve_extract_view(self)
}

/// Mutably fetches the given component from this view.
#[inline(always)]
fn component_mut<C>(&mut self) -> &mut C
fn component_mut<'b, C>(&'b mut self) -> &'b mut C
where
Self: ViewHas<C>,
Self::Archetype: ArchetypeHas<C>
{
<Self as ViewHas<C>>::resolve_component_mut(self)
<Self::Archetype as ArchetypeHas<C>>::resolve_extract_view_mut(self)
}
}

/// A trait promising that an entity view has a given component.
///
/// Used for where bounds on functions that take a view as a generic type.
///
/// See [`View`] for the methods that this enables on a type.
///
/// Note that macros like `ecs_iter!` do not currently support these kinds of generics.
/// This is primarily an advanced feature as it requires manual ECS manipulation.
///
/// # Examples
///
/// ```
/// use gecs::prelude::*;
///
/// pub struct CompA(pub u32);
/// pub struct CompB(pub u32);
///
/// ecs_world! {
/// // Declare archetype ArchFoo with one component: CompA
/// ecs_archetype!(ArchFoo, CompA, CompB);
/// ecs_archetype!(ArchBar, CompA, CompB);
/// }
///
/// fn generic_access_comp_a<V>(view: &mut V) -> u32
/// where
/// V: ViewHas<CompA> + ViewHas<CompB>,
/// {
/// view.component::<CompA>().0 + view.component::<CompB>().0
/// }
///
/// fn generic_access(world: &mut EcsWorld, foo: Entity<ArchFoo>, bar: Entity<ArchBar>) {
/// let mut view_foo = world.archetype_mut::<ArchFoo>().view(foo).unwrap();
/// let val_foo = generic_access_comp_a(&mut view_foo);
///
/// let mut view_bar = world.archetype_mut::<ArchBar>().view(bar).unwrap();
/// let val_bar = generic_access_comp_a(&mut view_bar);
///
/// println!("{} {}", val_foo, val_bar);
/// }
///
/// # fn main() {} // Not actually running anything here
/// ```
pub trait ViewHas<C>: View {
#[doc(hidden)]
fn resolve_component(&self) -> &C;
#[doc(hidden)]
fn resolve_component_mut(&mut self) -> &mut C;
}

/// A `Borrow` is a borrowed reference to a specific entity's components within an archetype.
///
/// This can be used in generic functions to access components from entity handles. Note that this
Expand Down
56 changes: 56 additions & 0 deletions tests/test_generic.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
use gecs::prelude::*;

pub struct CompA(pub u32);
pub struct CompB(pub u32);

ecs_world! {
ecs_archetype!(
ArchFoo,
CompA,
CompB,
);
}

#[test]
pub fn test_generic_view() {
let mut world = EcsWorld::new();

let entity = world.create::<ArchFoo>((CompA(1), CompB(1)));

let mut view = world.view(entity).unwrap();
view_increment(&mut view);

assert_eq!(view.component::<CompA>().0, 2);
assert_eq!(view.component::<CompB>().0, 2);
}

#[test]
pub fn test_generic_view_get() {
let mut world = EcsWorld::new();

let entity = world.create::<ArchFoo>((CompA(1), CompB(1)));

view_get_increment(&mut world, entity);

let mut view = world.view(entity).unwrap();
assert_eq!(view.component::<CompA>().0, 2);
assert_eq!(view.component::<CompB>().0, 2);
}

fn view_increment<'a, V: View<'a>>(view: &mut V)
where
V::Archetype: ArchetypeHas<CompA> + ArchetypeHas<CompB>,
{
view.component_mut::<CompA>().0 += 1;
view.component_mut::<CompB>().0 += 1;
}

fn view_get_increment<W, A>(world: &mut W, entity: Entity<A>)
where
W: WorldHas<A>,
A: ArchetypeHas<CompA> + ArchetypeHas<CompB>,
{
let mut view = world.view(entity).unwrap();
view.component_mut::<CompA>().0 += 1;
view.component_mut::<CompB>().0 += 1;
}

0 comments on commit afda315

Please sign in to comment.