Indexing a subset of fields

I have a design question involving struct indexing and field level access. I'm trying to store a reference to a field, and/or the field offset(?) itself.
The intention is to be able to associate the field with an intermediate value that is operated on over time, periodically writing back the value. An arbitrary number of these operations are intended to be composed and acting at once, targeting different fields with different update rates, etc. This is used to animate things like positions and colors, but any floating point property is valid.

I'd like to avoid copying the whole struct for each property set. I'm updating some arbitrary subset of fields and that data padding will add up quickly.
I can retrieve the actual struct to write back the data, but I'm having trouble finding a good way to map each value back to it's field in the struct.

This is essentially a domain-specific compressor. I'm using specs to manage entities and compose units of functionality.

My first attempt at a design has resulted in implementing IndexMut and using indexing to associate the values. The cost of a usize per field isn't great, but probably better than cloning the whole struct to update a single property. Buuuuut it's a lot of manual implementation. Ideally I can find a mechanism that is derivable or in the best case a zero cost reference.

My other thought was a proc-macro to generate some kind of serialization/deserialization mechanism. Perhaps there is a clever solution with lambdas I'm missing.
My big goal is to be able to trivially add new structs with the minimum amount of mapping code and/or boilerplate.

Ideally I can just create an array of tuples of references to fields and paired data, and pass that, dereferencing it where I do the work, but that might violate memory safety. This should be threadsafe-ish.

Interested in other people's thoughts and design patterns.

I saw people having stuff like:

enum Field {
    Bar,
    Baz,
    ...
}

struct Foo {
  fields: [u64, Field::COUNT],
}

foo.fields[Field::Bar as usize] = 42;

This allows you iterating and working generically over fields with ease while field access is still readable.

1 Like

That makes sense, a lot of the indexing examples use a similar layout.
I was hoping to avoid an enum, it would be really nice to be able to just apply this to any given struct. Ultimately that might be too much to ask.

If you have an array of those structs, you may also try step out of oop thinking and try dod, for example by having an array for each field instead of arrays of structs. And in general dod requires you to analyze the flow of the data in a relational (like in databases) way.

Interestingly enough, the larger system is dod, executing joins to relate data.
The issue I had when designing was that I still need to make a bespoke implementation for each type I want to support. Having a bunch of loose floats in massive arrays would be easy to index to, but an organizational nightmare!

I'm essentially trying to have it both ways :sweat_smile:
At the moment it sounds like just implementing Index and/or IndexMut is the "correct" way to get the functionality I want while still having structured data.

I recommend having enough use cases at first, and only then coming up with abstractions :sweat_smile:

By the way, by any chance, do you have the source code available?