#SystemParam / SystemParamMut pattern

14 messages · Page 1 of 1 (latest)

celest cliff
#

I find myself often implementing the following pattern, where I create a separate version of a SystemParam that operates on read-only data instead of mutable data:


#[derive(SystemParam)]
pub struct ChunkMapper<'w, 's> {
    map: Res<'w, ChunkMap>,
    chunks: Query<'w, 's, &'static Chunk, With<IsChunk>>,
}

impl<'w, 's> ChunkMapper<'w, 's> {
    pub fn get_chunk(&self, position: &ChunkPos) -> Option<&Chunk> {
        let entity = self.map.get(position)?;
        self.chunks.get(*entity).ok()
    }
}

#[derive(SystemParam)]
pub struct ChunkMapperMut<'w, 's> {
    map: Res<'w, ChunkMap>,
    chunks: Query<'w, 's, &'static mut Chunk, With<IsChunk>>,
}

impl<'w, 's> ChunkMapperMut<'w, 's> {
    pub fn get_chunk(&self, position: &ChunkPos) -> Option<&Chunk> {
        let entity = self.map.get(position)?;
        self.chunks.get(*entity).ok()
    }

    pub fn get_chunk_mut(&mut self, position: &ChunkPos) -> Option<Mut<Chunk>> {
        let entity = self.map.get(position)?;
        self.chunks.get_mut(*entity).ok()
    }
}

I do this to avoid conflicts.

How can I make this pattern simpler?
AFAIK it's not possible to use Traits for this, due to type restrictions around Query

long pebble
#

The ? operator will help the readability of those methods a lot if you can make it work

young vessel
#

If you're wanting to avoid duplication, you could also create a helper function

#

Or use a macro to generate part of the impls

celest cliff
# young vessel Or use a macro to generate part of the impls

macro is a good suggestion

Ideally, the api would look like this, though:

fn some_system(
  mapper: ChunkMapper,
) {
  // ...
}

fn mut_system(
  mut mapper: ChunkMapperMut,
) {
  // ...
}

into

fn some_system(
  mapper: ChunkMapper,
) {
  // ...
}

fn mut_system(
  mut mapper: ChunkMapper,
) {
  // ...
}
long pebble
#

Adding a From impl from the mutable to the immutable form is also nice?

#

I ran into this same problem in LWIM though for gathering input types

#

And couldn't find a nice solution to the duplication

young vessel
#

I don't think Bevy could even special case on that since it's not really part of the type (unlike &mut)

long pebble
#

Yeah Rust needs "keyword generics" (or an effects system) in order to really make that work

celest cliff
#

unfortunate, though macros do well enough for what I need

young vessel
#

Yeah the alternative would be to create a couple extra traits, but personally I think a macro would be cleaner (surprisingly lol)