execution-plan: Macro for implementing Value on structs #40
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Background
The
Value
trait lets a Rust type be written to KittyCAD execution plan (KCEP) memory, and read back out of memory. The trait has two methods,into_parts()
(convert your type into a vec of KCEPPrimitive
) andfrom_parts()
(given a vec of KCEPPrimitive
, reconstruct your type).Problem
You have to be careful that your
into_parts()
andfrom_parts()
methods use the same order for the fields of your Rust struct. E.g. ifinto_parts()
outputs a vec with self.length and self.name, thenfrom_parts()
must assume its input struct is self.length then self.name.This is easy, but it's a manual process and a bit error-prone. Additionally, the implementation is pretty boilerplate -- the implementation of
Value
can easily be recursive if all your fields also implValue
.Also, if I'm being honest, handwriting implementations of these traits for every single type in our Modeling API is going to be a pretty big timesink, and it's likely that at some point I lose focus and make a mistake, like putting the fields in the wrong order.
Solution
Write a macro which generates an impl of Value for a given type. If the human programmer supplies a list of all fields, we can ensure they're being used in the same order in both
from_parts()
andinto_parts()
. And this is actually type-checked -- Rust won't compile the code if you supply an invalid field!TODO