rj00a / evenio

An event-driven Entity Component System
MIT License
137 stars 14 forks source link

Consider `Single`, `SingleMut` #59

Closed andrewgazelka closed 5 months ago

andrewgazelka commented 5 months ago

Single would do really well as a smart pointer IMO. Only issue is right now it has one extra &

impl<'a, Q: Query> Deref for Single<'a, Q> {
    type Target = Q::Item<'a>;

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

should really be

impl<'a, Q: Query> Deref for Single<'a, Q> {
    type Target = Q::Item<'a>;

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

(note no &)

Of course this isn't possible given Deref def. I think the best way around this would be to have

Single<TheComponent>

and

SingleMut<TheComponent>

any other thoughts?

andrewgazelka commented 5 months ago

Actually, I looked into it and I see that it actually doesn't really make sense to do, probably, just because you do actually have multiple things in the query a lot of the time. So I'm going to close this for now, but let me know if you think of something else.

rj00a commented 5 months ago

I'm actually in favor of this change. I suspect 99% of the time users only care about a single component on the singleton entity. If Single<(&A, &B)> is needed, you could always just use a plain Query. (We should probably add a .single() method on Query to make that easier).

andrewgazelka commented 5 months ago

I'm actually in favor of this change. I suspect 99% of the time users only care about a single component on the singleton entity. If Single<(&A, &B)> is needed, you could always just use a plain Query. (We should probably add a .single() method on Query to make that easier).

This sounds like a great idea. I'm totally for this.

andrewgazelka commented 5 months ago

I made a hacky one here

#[derive(HandlerParam)]
pub struct Singleton<'a, T>
where
    T: Component<Mutability = evenio::mutability::Mutable>,
{
    single: Single<'a, &'static mut T>,
}

impl<'a, T> Deref for Singleton<'a, T>
where
    T: Component<Mutability = evenio::mutability::Mutable>,
{
    type Target = T;

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

impl<'a, T> DerefMut for Singleton<'a, T>
where
    T: Component<Mutability = evenio::mutability::Mutable>,
{
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.single.0
    }
}

Although I would agree, I think we should use and refactor Single.

Also wondering should we have Single and SingleMut? I feel 99% of the cases people will want to use the mutable version unless it doesn't impl evenio::mutability::Mutable.

rj00a commented 5 months ago

I'm in favor of both Single and SingleMut. I think it's good style to only use as much mutability as needed. It could also avoid unnecessary access conflicts e.g. when custom handler params have Single embedded in them.