Representing Individual Struct Fields & Enum Variants with a Derived Enum

Hello all, I am seeking to have something like persistent data structures (though probably what I am trying to implement deviates from what is formally called "persistent data structures"), and I am trying to use rust's enum system to do this.
Here is what I was thinking:

#[derive(WithState)]
// The type-state `<State>` generic isn't as important to the concept,
// but here it shows the 2 kinds of values I am working with: those that are assigned directly (like `i32`)
// and those who recursively have `EnumValue`s (see below) applied to them (like `ChildState<State>`)
struct ParentState<State> {
	state: PhantomData<State>,
	primitive_scalar: i32,
	primitive_list: Vec<i32>,
	state_scalar: ChildState<State>,
	state_map: BTreeMap<String, ChildState<State>>,
}

The derive(WithState) macro would create everything below:

Type aliases (including in this post for context)

type Parent = ParentState<Checked>;
type UncheckedParent = ParentState<Unchecked>;

EnumValue (there might be a better word for this)

  • Basically field_name as PascalCase storing the value (-At suffixed for indexed/keyed values)
  • The first variant value is the type of the field, unless it has as well, in which case it is a {struct}Value as well.
  • The proc macro tries to parse the kind of value from the syn::Type, but they can be overridden with macro attributes.
enum ParentValue {
	PrimitiveScalar(i32),
	PrimitiveListAt(i32, usize),
	StateScalar(ChildValue),
	StateMapAt(ChildValue, String),
}

Set/Apply Change/Value

  • A method to apply the value/change to the struct in any state, returning it in the Unchecked state
fn apply(&mut self, value: ParentValue) -> UncheckedParent {
	// ...
	match {
		ParentValue::PrimitiveScalar(value) => {
			self.primitive_scalar = value;
		},
		ParentValue::PrimitiveListAt(value, key) => {
			if let Some(inner_value) = self.primitive_list.get_mut(&key) {
				*inner_value = value;
			}
		},
		// and the same but calling `.apply(value)` instead of `= value`
		ParentValue::StateScalar(value) => {
			self.state_scalar.apply(value);
		},
		ParentValue::StateMapAt(value, key) => {
			if let Some(inner_value) = self.state_map.get_mut(&key) {
				inner_value.apply(value);
			}
		},
		// ...
		
	}
	// ...
}
  • I have been able to write proc macros to do it for structs, but I'm not sure how I should approach deriving on enums.
  • I'm asking for suggestions regarding enums because I can really only think of a neat/clean way to do it for anything other than variants with a single unnamed field.
  • I also welcome any other feedback and criticism with suggestions for improvement on any of this design.

Thanks anyone for any time you spend considering this, I appreciate it.