The core data structure is the classic "hash-map-in-a-resource" design. When designing this, we want to make the "fast enough, robust path" really obvious and easy, but avoid requiring it, to allow for easy refactors to custom update strategies as perf characteristics are refined in each project.

NOTE: the current design assumes uniquness. That might not be desirable!

#[derive(Resource)]
struct Index<C: Component + PartialEq, L: Lookup<Key=C>> {
    // Might be a hashmap, a btreemap, or even a vector
    storage: L
}

// All of the methods are defined by forwarding to L, with plumbing provided via the Lookup trait 
impl Index {
    fn find(&self, c: &C) -> Option<Entity> {}
    
    fn contains(&self, c: &C) -> bool {}
    
    
    fn insert(&mut self, c: C) -> Option<Entity>{
        
    }
    
    // Save on expensive cloning for large data structures
    fn insert_by_hash<C: Hash, L: HashBackedLookup>(&mut self, c: &C){
        
    }
    
    fn remove(&mut self, c: &C) -> Option<Entity>; 
}

This is typically maintained via a set of hooks with an immutable underlying component. These are provided, but must be manually added by the user.

To use:

fn get_left_hand_position(query: Query<&Transform>, index: Res<Index<Name>>) -> bevy::Result {
    let left_hand_entity = index.find("left_hand")?;
    let left_hand_position = query.get(left_hand_entity)?;
}