-
Notifications
You must be signed in to change notification settings - Fork 45
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
Program memory should not store JSON #1130
Comments
We basically want a model for what sorts of values exist in KCL. Here's my proposal for what KCL types exist.
Each of these would be a variant of If we do this, then |
As a KCL user, I like the idea of making SketchGroup and other things be Objects like any other user-defined object. My only concern would be whether we can represent all the things we need internally. But if we can do that, I think this is a good idea. |
I'm looking at the definition of If I were doing this, it seems big enough that I'd probably do it as a separate change, i.e. one PR to replace JSON with booleans, integers, floats, and strings. Then after it's merged, a second PR to collapse the rest into KclObjects. Even just the first PR should fix #3338 and other issues. |
I'll probably define trait AsKclObject {
fn into(&self) -> KclObject
fn from(KclObject) -> Result<Self, KclError>
} and impl this for types like SketchGroup and ExtrudeGroup and various types we send to the API. At some point in the future we can make a derive macro if we want. Then I'll also have trait AsKclValue {
fn into(&self) -> KclValue
fn from(KclValue) -> Result<Self, KclError>
} this will be implemented for ints, floats, strings etc by mapping them to/from the KclValue enum. We'll have a blanket impl for any T that impls AsKclObject. |
To clarify, this is what I propose as a first step to reduce the downstream impact. I believe this would fix #3338 because the SketchGroup would be stored as a value in the If you're doing the change, it's up to you whether you want to try to do it all at once, like in your comment above. pub enum KclValue {
// I don't want to get hung up on this. I think we use null in a couple
// places. This is a replacement for that. It would be nice to have
// something for when a function has no meaningful return value, instead of
// Option::None.
Unit,
Boolean(bool),
String(String),
Integer(i64),
Float(f64),
Array(Vec<KclValue>),
Object(HashMap<String, KclValue>),
// Everything below is unchanged.
TagIdentifier(Box<TagIdentifier>),
TagDeclarator(Box<TagDeclarator>),
Plane(Box<Plane>),
Face(Box<Face>),
SketchGroup(Box<SketchGroup>),
SketchGroups {
value: Vec<Box<SketchGroup>>,
},
ExtrudeGroup(Box<ExtrudeGroup>),
ExtrudeGroups {
value: Vec<Box<ExtrudeGroup>>,
},
ImportedGeometry(ImportedGeometry),
#[ts(skip)]
Function {
#[serde(skip)]
func: Option<MemoryFunction>,
expression: Box<FunctionExpression>,
memory: Box<ProgramMemory>,
#[serde(rename = "__meta")]
meta: Vec<Metadata>,
},
} |
This defines: - serde_kcl::Value - serde_kcl::Object - serde_kcl::to_val (takes a Rust type and 'serializes' it into KCL object) All similar to their equivalents in `serde_json`. Part of #1130
This defines: - serde_kcl::Value - serde_kcl::Object - serde_kcl::to_val (takes a Rust type and 'serializes' it into KCL object) All similar to their equivalents in `serde_json`. Part of #1130
The experiment of "serialize all values into JSON and just store JSON everywhere" is not looking good. Lee's L-system program is very slow because it spends most of its time repeatedly deserializing sketchgroups. I also don't think this approach will let us store KCL functions -- how would you serialize a KCL function into JSON? So, I think we should return to the proposal above, i.e. a |
Background
KCL program memory can store various different values, defined by the MemoryItem enum.
One case is "UserVal" which ultimately just stores
serde_json::Value
(see definition of UserVal). User values are serialized into JSON before storing them in program memory. Reading from memory deserializes the value into its expected type, and returns a KCL type error if the value couldn't be deserialized into the right type.Problem
This works OK but leads to bugs when developing the modeling-app wasm-lib. Why? Because so many types implement
serde::Deserialize
and you can try to deserialize a memory item into any of them. Even if those types never get written to memory ever! E.g. we never store aSocketAddrV4
in KCL program memory, but the rust compiler won't warn you if you try to request that from KCL memory. But it should! It should be a rust-compile-time error to request something we'd never expect to find in KCL memory.Solution
We should remove the
UserVal
variant fromMemoryItem
and add new variants for KCL primitive types (numbers, strings, the KCL none type, etc).This way, you ensure that reading values from memory requires that the value can at least be stored in memory.
The text was updated successfully, but these errors were encountered: