JoJoJet / bevy-trait-query

adds trait queries to the bevy game engine
Apache License 2.0
65 stars 11 forks source link

switch missing `TraitImplRegistry` to emit a warning instead of panicking #11

Closed soqb closed 1 year ago

soqb commented 1 year ago

Why?

The problem that I'm running into is this:

pub trait A {}

// zero or more B for each A
pub trait B {
    // exactly one A for each B
    type  MyA: A;
}

// private indirection to allow trait queries on traits with associated types.
#[bevy_trait_query::queryable]
trait BQueryable<TA: A>: B<MyA = TA> {}
impl<TA: A, U: B<MyA = TA>> BQueryable<TA> for U {}

pub struct APlugin<TA: A>(PhantomData<TA>);

fn get_all_b<TA: A>(query: Query<&dyn BQueryable<TA>>) {
    for bees in query.iter() {
        for b in bees.iter() {
            // do something with B
        }
    }
}

impl<TA: A + Component> Plugin for APlugin<TA> {
    fn build(&self, app: &mut App) {
        app.add_system(get_all_b::<TA>);
    }
}

pub struct BPlugin<TB: B>(PhantomData<TB>);

impl<TA: A, TB: B<MyA = TA> + Component> Plugin for BPlugin<TB> {
    fn build(&self, app: &mut App) {
        app.register_component_as::<dyn BQueryable<TA>, TB>();
    }
}

But since there may be zero BPlugins for an APlugin, when the system is initialized added and the registry is supposed to be sealed, there is no available registry because no components were registered for dyn BQueryable<TA> where TA == A in APlugin and the app panics.

Since TraitImplRegistry is private and that is relied upon for safety, inserted an empty TraitImplRegistry is not an option.

The only only current workaround (AFAIK) is to change the implementation of Plugin for APlugin to

fn build(&self, app: &mut App) {
    #[derive(Component)]
    struct TraitQueryWorkaround<UA: A>(PhantomData<UA>);
    impl<UA: A> B for TraitQueryWorkaround<UA> {
        type MyA = UA;
    }
    app.register_component_as::<dyn BQueryable<TA>, TraitQueryWorkaround<UA>>();
    app.add_system(get_all_b::<TA>);
}

which inserts a private, useless component into the registry which is not ideal.

Changes

This PR simply changes the panic to a warning and inserts an empty TraitImplRegistry just before sealing.