Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

systemdata and saveload_systemdata macros #704

Open
abesto opened this issue Jul 25, 2020 · 0 comments
Open

systemdata and saveload_systemdata macros #704

abesto opened this issue Jul 25, 2020 · 0 comments

Comments

@abesto
Copy link

abesto commented Jul 25, 2020

Description

I've created two (procedural) macros to write system data structs more concisely. I'm opening this "feature request" to 1. share them, 2. offer them as contributions or at least inspirations. The implementations currently live in https://github.com/abesto/rktrl/blob/master/rktrl_macros/src/lib.rs.

Motivation

systemdata

  • Minimize boilerplate
  • Standardize naming of fields, but allow overriding

Example usage

systemdata!(SpawnerSystemData(
    entities,
    write_storage(
        (serialize_me: SimpleMarker<SerializeMe>),
        AreaOfEffect,
        BlocksTile,
        [...]
        Viewshed,
    ),
    write((serialize_me_alloc: SimpleMarkerAllocator<SerializeMe>)),
    write_expect((rng: RandomNumberGenerator)),
    read_expect((spawn_requests: EventChannel<SpawnRequest>))
));

Generates roughly:

#[derive(SystemData)]
struct SpawnerSystemData<'a> {
    entities: Entities<'a>,

    serialize_me: WriteStorage<SimpleMarker<SerializeMe>, 'a>,
    area_of_effects: WriteStorage<AreaOfEffect, 'a>,
    [...]

    serialize_me_alloc: Write<SimpleMarkerAllocator<SerializeMe>, 'a>,
    [...]
}

saveload_systemdata

The implementation solves the 16 tuple size limit by chunking components into 16-sized tuples, so that actual saving would iterate over 16-tuples and save those one by one.

Example:

saveload_system_data!(
    components(
        AreaOfEffect,
        BlocksTile,
    )
    resources(Map, GameLog)
);

Generates roughly:

#[derive(SystemData)]
struct SaveSystemData<'a> {
    entities: Entities<'a>,
    components: ((ReadStorage<AreaOfEffect, 'a>, ReadStorage<BlocksTile, 'a>),),
    map: ReadExpect<Map, 'a>,
    game_log: ReadExpect<GameLog, 'a>
}


#[derive(SystemData)]
struct LoadSystemData<'a> {
    entities: Entities<'a>,
    components: ((WriteStorage<AreaOfEffect, 'a>, WriteStorage<BlocksTile, 'a>),),
    map: Write<Map, 'a>,
    game_log: Write<GameLog, 'a>
}

Drawbacks

  • More magic than is usual for specs
  • Error messages are sometimes hard to understand when macro usage is messed up
  • Builds on top of current specs_derive instead of integrating with it deeply

Unresolved questions

I'm using this in my hobby project happily, but have zero experience with production-ready macros. That's where I expect most of the problems (unknown to me currently) to creep in. I guess there's also bikeshedding to be done around the syntax.


I'd be happy to "formally" contribute these macros as a PR if it makes sense, and to put in some work iterating on them based on feedback.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant