diff --git a/src/wasm-lib/kcl/src/ast/types.rs b/src/wasm-lib/kcl/src/ast/types.rs index f1a2f1d7ac..bd1c7fcf97 100644 --- a/src/wasm-lib/kcl/src/ast/types.rs +++ b/src/wasm-lib/kcl/src/ast/types.rs @@ -23,7 +23,7 @@ use crate::{ docs::StdLibFn, errors::{KclError, KclErrorDetails}, executor::{ - BodyType, DynamicState, ExecutorContext, KclValue, Metadata, PipeInfo, ProgramMemory, SourceRange, + BodyType, DynamicState, ExecutorContext, KclValue, Metadata, PipeInfo, ProgramMemory, SketchGroup, SourceRange, StatementKind, TagEngineInfo, TagIdentifier, UserVal, }, parser::PIPE_OPERATOR, @@ -1356,10 +1356,13 @@ impl CallExpression { // TODO: This could probably be done in a better way, but as of now this was my only idea // and it works. match result { - KclValue::SketchGroup(ref sketch_group) => { - for (_, tag) in sketch_group.tags.iter() { - memory.update_tag(&tag.value, tag.clone())?; - } + KclValue::UserVal(ref mut uval) => { + uval.mutate(|sketch_group: &mut SketchGroup| { + for (_, tag) in sketch_group.tags.iter() { + memory.update_tag(&tag.value, tag.clone())?; + } + Ok::<_, KclError>(()) + })?; } KclValue::ExtrudeGroup(ref mut extrude_group) => { for value in &extrude_group.value { diff --git a/src/wasm-lib/kcl/src/executor.rs b/src/wasm-lib/kcl/src/executor.rs index 0e5e217a55..4d4e6289f1 100644 --- a/src/wasm-lib/kcl/src/executor.rs +++ b/src/wasm-lib/kcl/src/executor.rs @@ -203,13 +203,22 @@ impl Environment { } for (_, val) in self.bindings.iter_mut() { - if let KclValue::SketchGroup(ref mut sketch_group) = val { - if sketch_group.original_id == sg.original_id { - for tag in sg.tags.iter() { - sketch_group.tags.insert(tag.0.clone(), tag.1.clone()); - } + let KclValue::UserVal(v) = val else { continue }; + let meta = v.meta.clone(); + let maybe_sg: Result = serde_json::from_value(v.value.clone()); + let Ok(mut sketch_group) = maybe_sg else { + continue; + }; + + if sketch_group.original_id == sg.original_id { + for tag in sg.tags.iter() { + sketch_group.tags.insert(tag.0.clone(), tag.1.clone()); } } + *val = KclValue::UserVal(UserVal { + meta, + value: serde_json::to_value(sketch_group).expect("can always turn SketchGroup into JSON"), + }); } } } @@ -268,10 +277,7 @@ pub enum KclValue { TagDeclarator(Box), Plane(Box), Face(Box), - SketchGroup(Box), - SketchGroups { - value: Vec>, - }, + ExtrudeGroup(Box), ExtrudeGroups { value: Vec>, @@ -289,27 +295,8 @@ pub enum KclValue { } impl KclValue { - pub(crate) fn get_sketch_group_set(&self) -> Result { - match self { - KclValue::SketchGroup(s) => Ok(SketchGroupSet::SketchGroup(s.clone())), - KclValue::SketchGroups { value } => Ok(SketchGroupSet::SketchGroups(value.clone())), - KclValue::UserVal(value) => { - let value = value.value.clone(); - match value { - JValue::Null | JValue::Bool(_) | JValue::Number(_) | JValue::String(_) => Err(anyhow::anyhow!( - "Failed to deserialize sketch group set from JSON {}", - human_friendly_type(&value) - )), - JValue::Array(_) => serde_json::from_value::>>(value) - .map(SketchGroupSet::from) - .map_err(|e| anyhow::anyhow!("Failed to deserialize array of sketch groups from JSON: {}", e)), - JValue::Object(_) => serde_json::from_value::>(value) - .map(SketchGroupSet::from) - .map_err(|e| anyhow::anyhow!("Failed to deserialize sketch group from JSON: {}", e)), - } - } - _ => anyhow::bail!("Not a sketch group or sketch groups: {:?}", self), - } + pub(crate) fn new_user_val(meta: Vec, val: T) -> Self { + Self::UserVal(UserVal::set(meta, val)) } pub(crate) fn get_extrude_group_set(&self) -> Result { @@ -342,8 +329,6 @@ impl KclValue { KclValue::UserVal(u) => human_friendly_type(&u.value), KclValue::TagDeclarator(_) => "TagDeclarator", KclValue::TagIdentifier(_) => "TagIdentifier", - KclValue::SketchGroup(_) => "SketchGroup", - KclValue::SketchGroups { .. } => "SketchGroups", KclValue::ExtrudeGroup(_) => "ExtrudeGroup", KclValue::ExtrudeGroups { .. } => "ExtrudeGroups", KclValue::ImportedGeometry(_) => "ImportedGeometry", @@ -356,20 +341,14 @@ impl KclValue { impl From for KclValue { fn from(sg: SketchGroupSet) -> Self { - match sg { - SketchGroupSet::SketchGroup(sg) => KclValue::SketchGroup(sg), - SketchGroupSet::SketchGroups(sgs) => KclValue::SketchGroups { value: sgs }, - } + KclValue::UserVal(UserVal::set(sg.meta(), sg)) } } impl From>> for KclValue { fn from(sg: Vec>) -> Self { - if sg.len() == 1 { - KclValue::SketchGroup(sg[0].clone()) - } else { - KclValue::SketchGroups { value: sg } - } + let meta = sg.iter().flat_map(|sg| sg.meta.clone()).collect(); + KclValue::UserVal(UserVal::set(meta, sg)) } } @@ -428,6 +407,24 @@ pub enum SketchGroupSet { SketchGroups(Vec>), } +impl SketchGroupSet { + pub fn meta(&self) -> Vec { + match self { + SketchGroupSet::SketchGroup(sg) => sg.meta.clone(), + SketchGroupSet::SketchGroups(sg) => sg.iter().flat_map(|sg| sg.meta.clone()).collect(), + } + } +} + +impl From for Vec { + fn from(value: SketchGroupSet) -> Self { + match value { + SketchGroupSet::SketchGroup(sg) => vec![*sg], + SketchGroupSet::SketchGroups(sgs) => sgs.into_iter().map(|sg| *sg).collect(), + } + } +} + impl From for SketchGroupSet { fn from(sg: SketchGroup) -> Self { SketchGroupSet::SketchGroup(Box::new(sg)) @@ -641,6 +638,43 @@ pub struct UserVal { pub meta: Vec, } +impl UserVal { + /// If the UserVal matches the type `T`, return it. + pub fn get(&self) -> Option<(T, Vec)> { + let meta = self.meta.clone(); + // TODO: This clone might cause performance problems, it'll happen a lot. + let res: Result = serde_json::from_value(self.value.clone()); + if let Ok(t) = res { + Some((t, meta)) + } else { + None + } + } + + /// If the UserVal matches the type `T`, then mutate it via the given closure. + /// If the closure returns Err, the mutation won't be applied. + pub fn mutate(&mut self, mutate: F) -> Result<(), E> + where + T: serde::de::DeserializeOwned + Serialize, + F: FnOnce(&mut T) -> Result<(), E>, + { + let Some((mut val, meta)) = self.get::() else { + return Ok(()); + }; + mutate(&mut val)?; + *self = Self::set(meta, val); + Ok(()) + } + + /// Put the given value into this UserVal. + pub fn set(meta: Vec, val: T) -> Self { + Self { + meta, + value: serde_json::to_value(val).expect("all KCL values should be compatible with JSON"), + } + } +} + #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, ts_rs::TS, JsonSchema)] #[ts(export)] #[serde(tag = "type", rename_all = "camelCase")] @@ -720,11 +754,6 @@ impl From for Vec { KclValue::UserVal(u) => u.meta.iter().map(|m| m.source_range).collect(), KclValue::TagDeclarator(t) => t.into(), KclValue::TagIdentifier(t) => t.meta.iter().map(|m| m.source_range).collect(), - KclValue::SketchGroup(s) => s.meta.iter().map(|m| m.source_range).collect(), - KclValue::SketchGroups { value } => value - .iter() - .flat_map(|sg| sg.meta.iter().map(|m| m.source_range)) - .collect(), KclValue::ExtrudeGroup(e) => e.meta.iter().map(|m| m.source_range).collect(), KclValue::ExtrudeGroups { value } => value .iter() diff --git a/src/wasm-lib/kcl/src/std/args.rs b/src/wasm-lib/kcl/src/std/args.rs index 1e796a4887..541a7c8411 100644 --- a/src/wasm-lib/kcl/src/std/args.rs +++ b/src/wasm-lib/kcl/src/std/args.rs @@ -251,11 +251,11 @@ impl Args { FromArgs::from_args(self, 0) } - pub(crate) fn get_sketch_groups(&self) -> Result<(SketchGroupSet, Box), KclError> { + pub(crate) fn get_sketch_groups(&self) -> Result<(SketchGroupSet, SketchGroup), KclError> { FromArgs::from_args(self, 0) } - pub(crate) fn get_sketch_group(&self) -> Result, KclError> { + pub(crate) fn get_sketch_group(&self) -> Result { FromArgs::from_args(self, 0) } @@ -270,9 +270,7 @@ impl Args { FromArgs::from_args(self, 0) } - pub(crate) fn get_sketch_group_and_optional_tag( - &self, - ) -> Result<(Box, Option), KclError> { + pub(crate) fn get_sketch_group_and_optional_tag(&self) -> Result<(SketchGroup, Option), KclError> { FromArgs::from_args(self, 0) } @@ -283,7 +281,7 @@ impl Args { FromArgs::from_args(self, 0) } - pub(crate) fn get_data_and_sketch_group<'a, T>(&'a self) -> Result<(T, Box), KclError> + pub(crate) fn get_data_and_sketch_group<'a, T>(&'a self) -> Result<(T, SketchGroup), KclError> where T: serde::de::DeserializeOwned + FromArgs<'a>, { @@ -299,7 +297,7 @@ impl Args { pub(crate) fn get_data_and_sketch_group_and_tag<'a, T>( &'a self, - ) -> Result<(T, Box, Option), KclError> + ) -> Result<(T, SketchGroup, Option), KclError> where T: serde::de::DeserializeOwned + FromKclValue<'a> + Sized, { @@ -338,7 +336,7 @@ impl Args { FromArgs::from_args(self, 0) } - pub(crate) fn get_tag_to_number_sketch_group(&self) -> Result<(TagIdentifier, f64, Box), KclError> { + pub(crate) fn get_tag_to_number_sketch_group(&self) -> Result<(TagIdentifier, f64, SketchGroup), KclError> { FromArgs::from_args(self, 0) } @@ -550,15 +548,6 @@ impl<'a> FromKclValue<'a> for TagIdentifier { } } -impl<'a> FromKclValue<'a> for &'a SketchGroup { - fn from_mem_item(arg: &'a KclValue) -> Option { - let KclValue::SketchGroup(s) = arg else { - return None; - }; - Some(s.as_ref()) - } -} - macro_rules! impl_from_arg_via_json { ($typ:path) => { impl<'a> FromKclValue<'a> for $typ { @@ -608,6 +597,8 @@ impl_from_arg_via_json!(super::revolve::RevolveData); impl_from_arg_via_json!(super::sketch::SketchData); impl_from_arg_via_json!(crate::std::import::ImportFormat); impl_from_arg_via_json!(crate::std::polar::PolarCoordsData); +impl_from_arg_via_json!(SketchGroup); +impl_from_arg_via_json!(SketchGroupSet); impl_from_arg_via_json!(FaceTag); impl_from_arg_via_json!(String); impl_from_arg_via_json!(u32); @@ -618,24 +609,6 @@ impl_from_arg_via_json!(bool); impl_from_arg_for_array!(2); impl_from_arg_for_array!(3); -impl<'a> FromKclValue<'a> for &'a Box { - fn from_mem_item(arg: &'a KclValue) -> Option { - let KclValue::SketchGroup(s) = arg else { - return None; - }; - Some(s) - } -} - -impl<'a> FromKclValue<'a> for Box { - fn from_mem_item(arg: &'a KclValue) -> Option { - let KclValue::SketchGroup(s) = arg else { - return None; - }; - Some(s.to_owned()) - } -} - impl<'a> FromKclValue<'a> for Box { fn from_mem_item(arg: &'a KclValue) -> Option { let KclValue::ExtrudeGroup(s) = arg else { @@ -656,15 +629,16 @@ impl<'a> FromKclValue<'a> for ExtrudeGroupSet { arg.get_extrude_group_set().ok() } } -impl<'a> FromKclValue<'a> for SketchGroupSet { - fn from_mem_item(arg: &'a KclValue) -> Option { - arg.get_sketch_group_set().ok() - } -} impl<'a> FromKclValue<'a> for SketchSurfaceOrGroup { fn from_mem_item(arg: &'a KclValue) -> Option { match arg { - KclValue::SketchGroup(sg) => Some(Self::SketchGroup(sg.clone())), + KclValue::UserVal(uv) => { + if let Some((sg, _meta)) = uv.get() { + Some(Self::SketchGroup(sg)) + } else { + None + } + } KclValue::Plane(sg) => Some(Self::SketchSurface(SketchSurface::Plane(sg.clone()))), KclValue::Face(sg) => Some(Self::SketchSurface(SketchSurface::Face(sg.clone()))), _ => None, diff --git a/src/wasm-lib/kcl/src/std/extrude.rs b/src/wasm-lib/kcl/src/std/extrude.rs index 58b741bd5c..0a0081c4a9 100644 --- a/src/wasm-lib/kcl/src/std/extrude.rs +++ b/src/wasm-lib/kcl/src/std/extrude.rs @@ -76,7 +76,7 @@ async fn inner_extrude(length: f64, sketch_group_set: SketchGroupSet, args: Args let id = uuid::Uuid::new_v4(); // Extrude the element(s). - let sketch_groups: Vec> = sketch_group_set.into(); + let sketch_groups: Vec = sketch_group_set.into(); let mut extrude_groups = Vec::new(); for sketch_group in &sketch_groups { // Before we extrude, we need to enable the sketch mode. @@ -118,7 +118,7 @@ async fn inner_extrude(length: f64, sketch_group_set: SketchGroupSet, args: Args } pub(crate) async fn do_post_extrude( - sketch_group: Box, + sketch_group: SketchGroup, length: f64, id: Uuid, args: Args, @@ -155,7 +155,7 @@ pub(crate) async fn do_post_extrude( })); }; - let mut sketch_group = *sketch_group.clone(); + let mut sketch_group = sketch_group.clone(); // If we were sketching on a face, we need the original face id. if let SketchSurface::Face(ref face) = sketch_group.on { diff --git a/src/wasm-lib/kcl/src/std/revolve.rs b/src/wasm-lib/kcl/src/std/revolve.rs index 3b2bf4fd37..b91940a0fd 100644 --- a/src/wasm-lib/kcl/src/std/revolve.rs +++ b/src/wasm-lib/kcl/src/std/revolve.rs @@ -102,7 +102,7 @@ impl RevolveAxisAndOrigin { /// Revolve a sketch around an axis. pub async fn revolve(args: Args) -> Result { - let (data, sketch_group): (RevolveData, Box) = args.get_data_and_sketch_group()?; + let (data, sketch_group): (RevolveData, SketchGroup) = args.get_data_and_sketch_group()?; let extrude_group = inner_revolve(data, sketch_group, args).await?; Ok(KclValue::ExtrudeGroup(extrude_group)) @@ -249,7 +249,7 @@ pub async fn revolve(args: Args) -> Result { }] async fn inner_revolve( data: RevolveData, - sketch_group: Box, + sketch_group: SketchGroup, args: Args, ) -> Result, KclError> { if let Some(angle) = data.angle { diff --git a/src/wasm-lib/kcl/src/std/segment.rs b/src/wasm-lib/kcl/src/std/segment.rs index d67d21b3ca..fed858a555 100644 --- a/src/wasm-lib/kcl/src/std/segment.rs +++ b/src/wasm-lib/kcl/src/std/segment.rs @@ -108,7 +108,7 @@ pub async fn last_segment_x(args: Args) -> Result { #[stdlib { name = "lastSegX", }] -fn inner_last_segment_x(sketch_group: Box, args: Args) -> Result { +fn inner_last_segment_x(sketch_group: SketchGroup, args: Args) -> Result { let last_line = sketch_group .value .last() @@ -151,7 +151,7 @@ pub async fn last_segment_y(args: Args) -> Result { #[stdlib { name = "lastSegY", }] -fn inner_last_segment_y(sketch_group: Box, args: Args) -> Result { +fn inner_last_segment_y(sketch_group: SketchGroup, args: Args) -> Result { let last_line = sketch_group .value .last() @@ -281,7 +281,7 @@ pub async fn angle_to_match_length_x(args: Args) -> Result { fn inner_angle_to_match_length_x( tag: &TagIdentifier, to: f64, - sketch_group: Box, + sketch_group: SketchGroup, args: Args, ) -> Result { let line = args.get_tag_engine_info(tag)?; @@ -347,7 +347,7 @@ pub async fn angle_to_match_length_y(args: Args) -> Result { fn inner_angle_to_match_length_y( tag: &TagIdentifier, to: f64, - sketch_group: Box, + sketch_group: SketchGroup, args: Args, ) -> Result { let line = args.get_tag_engine_info(tag)?; diff --git a/src/wasm-lib/kcl/src/std/shapes.rs b/src/wasm-lib/kcl/src/std/shapes.rs index 967d38160b..1c80c2d9d4 100644 --- a/src/wasm-lib/kcl/src/std/shapes.rs +++ b/src/wasm-lib/kcl/src/std/shapes.rs @@ -27,7 +27,7 @@ pub async fn circle(args: Args) -> Result { args.get_circle_args()?; let sketch_group = inner_circle(center, radius, sketch_surface_or_group, tag, args).await?; - Ok(KclValue::SketchGroup(sketch_group)) + Ok(KclValue::new_user_val(sketch_group.meta.clone(), sketch_group)) } /// Construct a 2-dimensional circle, of the specified radius, centered at @@ -60,7 +60,7 @@ async fn inner_circle( sketch_surface_or_group: SketchSurfaceOrGroup, tag: Option, args: Args, -) -> Result, KclError> { +) -> Result { let sketch_surface = match sketch_surface_or_group { SketchSurfaceOrGroup::SketchSurface(surface) => surface, SketchSurfaceOrGroup::SketchGroup(group) => group.on, diff --git a/src/wasm-lib/kcl/src/std/sketch.rs b/src/wasm-lib/kcl/src/std/sketch.rs index 4359170f5c..0f19d060d4 100644 --- a/src/wasm-lib/kcl/src/std/sketch.rs +++ b/src/wasm-lib/kcl/src/std/sketch.rs @@ -90,11 +90,11 @@ pub enum StartOrEnd { /// Draw a line to a point. pub async fn line_to(args: Args) -> Result { - let (to, sketch_group, tag): ([f64; 2], Box, Option) = + let (to, sketch_group, tag): ([f64; 2], SketchGroup, Option) = args.get_data_and_sketch_group_and_tag()?; let new_sketch_group = inner_line_to(to, sketch_group, tag, args).await?; - Ok(KclValue::SketchGroup(new_sketch_group)) + Ok(KclValue::new_user_val(new_sketch_group.meta.clone(), new_sketch_group)) } /// Draw a line from the current origin to some absolute (x, y) point. @@ -114,10 +114,10 @@ pub async fn line_to(args: Args) -> Result { }] async fn inner_line_to( to: [f64; 2], - sketch_group: Box, + sketch_group: SketchGroup, tag: Option, args: Args, -) -> Result, KclError> { +) -> Result { let from = sketch_group.current_pen_position()?; let id = uuid::Uuid::new_v4(); @@ -161,11 +161,11 @@ async fn inner_line_to( /// Draw a line to a point on the x-axis. pub async fn x_line_to(args: Args) -> Result { - let (to, sketch_group, tag): (f64, Box, Option) = + let (to, sketch_group, tag): (f64, SketchGroup, Option) = args.get_data_and_sketch_group_and_tag()?; let new_sketch_group = inner_x_line_to(to, sketch_group, tag, args).await?; - Ok(KclValue::SketchGroup(new_sketch_group)) + Ok(KclValue::new_user_val(new_sketch_group.meta.clone(), new_sketch_group)) } /// Draw a line parallel to the X axis, that ends at the given X. @@ -196,10 +196,10 @@ pub async fn x_line_to(args: Args) -> Result { }] async fn inner_x_line_to( to: f64, - sketch_group: Box, + sketch_group: SketchGroup, tag: Option, args: Args, -) -> Result, KclError> { +) -> Result { let from = sketch_group.current_pen_position()?; let new_sketch_group = inner_line_to([to, from.y], sketch_group, tag, args).await?; @@ -209,11 +209,11 @@ async fn inner_x_line_to( /// Draw a line to a point on the y-axis. pub async fn y_line_to(args: Args) -> Result { - let (to, sketch_group, tag): (f64, Box, Option) = + let (to, sketch_group, tag): (f64, SketchGroup, Option) = args.get_data_and_sketch_group_and_tag()?; let new_sketch_group = inner_y_line_to(to, sketch_group, tag, args).await?; - Ok(KclValue::SketchGroup(new_sketch_group)) + Ok(KclValue::new_user_val(new_sketch_group.meta.clone(), new_sketch_group)) } /// Draw a line parallel to the Y axis, that ends at the given Y. @@ -237,10 +237,10 @@ pub async fn y_line_to(args: Args) -> Result { }] async fn inner_y_line_to( to: f64, - sketch_group: Box, + sketch_group: SketchGroup, tag: Option, args: Args, -) -> Result, KclError> { +) -> Result { let from = sketch_group.current_pen_position()?; let new_sketch_group = inner_line_to([from.x, to], sketch_group, tag, args).await?; @@ -249,11 +249,11 @@ async fn inner_y_line_to( /// Draw a line. pub async fn line(args: Args) -> Result { - let (delta, sketch_group, tag): ([f64; 2], Box, Option) = + let (delta, sketch_group, tag): ([f64; 2], SketchGroup, Option) = args.get_data_and_sketch_group_and_tag()?; let new_sketch_group = inner_line(delta, sketch_group, tag, args).await?; - Ok(KclValue::SketchGroup(new_sketch_group)) + Ok(KclValue::new_user_val(new_sketch_group.meta.clone(), new_sketch_group)) } /// Draw a line relative to the current origin to a specified (x, y) away @@ -285,10 +285,10 @@ pub async fn line(args: Args) -> Result { }] async fn inner_line( delta: [f64; 2], - sketch_group: Box, + sketch_group: SketchGroup, tag: Option, args: Args, -) -> Result, KclError> { +) -> Result { let from = sketch_group.current_pen_position()?; let to = [from.x + delta[0], from.y + delta[1]]; @@ -334,11 +334,11 @@ async fn inner_line( /// Draw a line on the x-axis. pub async fn x_line(args: Args) -> Result { - let (length, sketch_group, tag): (f64, Box, Option) = + let (length, sketch_group, tag): (f64, SketchGroup, Option) = args.get_data_and_sketch_group_and_tag()?; let new_sketch_group = inner_x_line(length, sketch_group, tag, args).await?; - Ok(KclValue::SketchGroup(new_sketch_group)) + Ok(KclValue::new_user_val(new_sketch_group.meta.clone(), new_sketch_group)) } /// Draw a line relative to the current origin to a specified distance away @@ -368,20 +368,20 @@ pub async fn x_line(args: Args) -> Result { }] async fn inner_x_line( length: f64, - sketch_group: Box, + sketch_group: SketchGroup, tag: Option, args: Args, -) -> Result, KclError> { +) -> Result { inner_line([length, 0.0], sketch_group, tag, args).await } /// Draw a line on the y-axis. pub async fn y_line(args: Args) -> Result { - let (length, sketch_group, tag): (f64, Box, Option) = + let (length, sketch_group, tag): (f64, SketchGroup, Option) = args.get_data_and_sketch_group_and_tag()?; let new_sketch_group = inner_y_line(length, sketch_group, tag, args).await?; - Ok(KclValue::SketchGroup(new_sketch_group)) + Ok(KclValue::new_user_val(new_sketch_group.meta.clone(), new_sketch_group)) } /// Draw a line relative to the current origin to a specified distance away @@ -406,10 +406,10 @@ pub async fn y_line(args: Args) -> Result { }] async fn inner_y_line( length: f64, - sketch_group: Box, + sketch_group: SketchGroup, tag: Option, args: Args, -) -> Result, KclError> { +) -> Result { inner_line([0.0, length], sketch_group, tag, args).await } @@ -431,11 +431,11 @@ pub enum AngledLineData { /// Draw an angled line. pub async fn angled_line(args: Args) -> Result { - let (data, sketch_group, tag): (AngledLineData, Box, Option) = + let (data, sketch_group, tag): (AngledLineData, SketchGroup, Option) = args.get_data_and_sketch_group_and_tag()?; let new_sketch_group = inner_angled_line(data, sketch_group, tag, args).await?; - Ok(KclValue::SketchGroup(new_sketch_group)) + Ok(KclValue::new_user_val(new_sketch_group.meta.clone(), new_sketch_group)) } /// Draw a line segment relative to the current origin using the polar @@ -460,10 +460,10 @@ pub async fn angled_line(args: Args) -> Result { }] async fn inner_angled_line( data: AngledLineData, - sketch_group: Box, + sketch_group: SketchGroup, tag: Option, args: Args, -) -> Result, KclError> { +) -> Result { let from = sketch_group.current_pen_position()?; let (angle, length) = match data { AngledLineData::AngleAndLengthNamed { angle, length } => (angle, length), @@ -520,11 +520,11 @@ async fn inner_angled_line( /// Draw an angled line of a given x length. pub async fn angled_line_of_x_length(args: Args) -> Result { - let (data, sketch_group, tag): (AngledLineData, Box, Option) = + let (data, sketch_group, tag): (AngledLineData, SketchGroup, Option) = args.get_data_and_sketch_group_and_tag()?; let new_sketch_group = inner_angled_line_of_x_length(data, sketch_group, tag, args).await?; - Ok(KclValue::SketchGroup(new_sketch_group)) + Ok(KclValue::new_user_val(new_sketch_group.meta.clone(), new_sketch_group)) } /// Create a line segment from the current 2-dimensional sketch origin @@ -545,10 +545,10 @@ pub async fn angled_line_of_x_length(args: Args) -> Result { }] async fn inner_angled_line_of_x_length( data: AngledLineData, - sketch_group: Box, + sketch_group: SketchGroup, tag: Option, args: Args, -) -> Result, KclError> { +) -> Result { let (angle, length) = match data { AngledLineData::AngleAndLengthNamed { angle, length } => (angle, length), AngledLineData::AngleAndLengthPair(pair) => (pair[0], pair[1]), @@ -588,11 +588,11 @@ pub struct AngledLineToData { /// Draw an angled line to a given x coordinate. pub async fn angled_line_to_x(args: Args) -> Result { - let (data, sketch_group, tag): (AngledLineToData, Box, Option) = + let (data, sketch_group, tag): (AngledLineToData, SketchGroup, Option) = args.get_data_and_sketch_group_and_tag()?; let new_sketch_group = inner_angled_line_to_x(data, sketch_group, tag, args).await?; - Ok(KclValue::SketchGroup(new_sketch_group)) + Ok(KclValue::new_user_val(new_sketch_group.meta.clone(), new_sketch_group)) } /// Create a line segment from the current 2-dimensional sketch origin @@ -614,10 +614,10 @@ pub async fn angled_line_to_x(args: Args) -> Result { }] async fn inner_angled_line_to_x( data: AngledLineToData, - sketch_group: Box, + sketch_group: SketchGroup, tag: Option, args: Args, -) -> Result, KclError> { +) -> Result { let from = sketch_group.current_pen_position()?; let AngledLineToData { angle, to: x_to } = data; @@ -645,12 +645,12 @@ async fn inner_angled_line_to_x( /// Draw an angled line of a given y length. pub async fn angled_line_of_y_length(args: Args) -> Result { - let (data, sketch_group, tag): (AngledLineData, Box, Option) = + let (data, sketch_group, tag): (AngledLineData, SketchGroup, Option) = args.get_data_and_sketch_group_and_tag()?; let new_sketch_group = inner_angled_line_of_y_length(data, sketch_group, tag, args).await?; - Ok(KclValue::SketchGroup(new_sketch_group)) + Ok(KclValue::new_user_val(new_sketch_group.meta.clone(), new_sketch_group)) } /// Create a line segment from the current 2-dimensional sketch origin @@ -673,10 +673,10 @@ pub async fn angled_line_of_y_length(args: Args) -> Result { }] async fn inner_angled_line_of_y_length( data: AngledLineData, - sketch_group: Box, + sketch_group: SketchGroup, tag: Option, args: Args, -) -> Result, KclError> { +) -> Result { let (angle, length) = match data { AngledLineData::AngleAndLengthNamed { angle, length } => (angle, length), AngledLineData::AngleAndLengthPair(pair) => (pair[0], pair[1]), @@ -705,11 +705,11 @@ async fn inner_angled_line_of_y_length( /// Draw an angled line to a given y coordinate. pub async fn angled_line_to_y(args: Args) -> Result { - let (data, sketch_group, tag): (AngledLineToData, Box, Option) = + let (data, sketch_group, tag): (AngledLineToData, SketchGroup, Option) = args.get_data_and_sketch_group_and_tag()?; let new_sketch_group = inner_angled_line_to_y(data, sketch_group, tag, args).await?; - Ok(KclValue::SketchGroup(new_sketch_group)) + Ok(KclValue::new_user_val(new_sketch_group.meta.clone(), new_sketch_group)) } /// Create a line segment from the current 2-dimensional sketch origin @@ -731,10 +731,10 @@ pub async fn angled_line_to_y(args: Args) -> Result { }] async fn inner_angled_line_to_y( data: AngledLineToData, - sketch_group: Box, + sketch_group: SketchGroup, tag: Option, args: Args, -) -> Result, KclError> { +) -> Result { let from = sketch_group.current_pen_position()?; let AngledLineToData { angle, to: y_to } = data; @@ -776,10 +776,10 @@ pub struct AngledLineThatIntersectsData { /// Draw an angled line that intersects with a given line. pub async fn angled_line_that_intersects(args: Args) -> Result { - let (data, sketch_group, tag): (AngledLineThatIntersectsData, Box, Option) = + let (data, sketch_group, tag): (AngledLineThatIntersectsData, SketchGroup, Option) = args.get_data_and_sketch_group_and_tag()?; let new_sketch_group = inner_angled_line_that_intersects(data, sketch_group, tag, args).await?; - Ok(KclValue::SketchGroup(new_sketch_group)) + Ok(KclValue::new_user_val(new_sketch_group.meta.clone(), new_sketch_group)) } /// Draw an angled line from the current origin, constructing a line segment @@ -806,10 +806,10 @@ pub async fn angled_line_that_intersects(args: Args) -> Result, + sketch_group: SketchGroup, tag: Option, args: Args, -) -> Result, KclError> { +) -> Result { let intersect_path = args.get_tag_engine_info(&data.intersect_tag)?; let path = intersect_path.path.clone().ok_or_else(|| { KclError::Type(KclErrorDetails { @@ -835,7 +835,7 @@ pub async fn start_sketch_at(args: Args) -> Result { let data: [f64; 2] = args.get_data()?; let sketch_group = inner_start_sketch_at(data, args).await?; - Ok(KclValue::SketchGroup(sketch_group)) + Ok(KclValue::new_user_val(sketch_group.meta.clone(), sketch_group)) } /// Start a new 2-dimensional sketch at a given point on the 'XY' plane. @@ -872,7 +872,7 @@ pub async fn start_sketch_at(args: Args) -> Result { #[stdlib { name = "startSketchAt", }] -async fn inner_start_sketch_at(data: [f64; 2], args: Args) -> Result, KclError> { +async fn inner_start_sketch_at(data: [f64; 2], args: Args) -> Result { // Let's assume it's the XY plane for now, this is just for backwards compatibility. let xy_plane = PlaneData::XY; let sketch_surface = inner_start_sketch_on(SketchData::Plane(xy_plane), None, args.clone()).await?; @@ -1204,7 +1204,7 @@ pub async fn start_profile_at(args: Args) -> Result { args.get_data_and_sketch_surface()?; let sketch_group = inner_start_profile_at(start, sketch_surface, tag, args).await?; - Ok(KclValue::SketchGroup(sketch_group)) + Ok(KclValue::new_user_val(sketch_group.meta.clone(), sketch_group)) } /// Start a new profile at a given point. @@ -1249,7 +1249,7 @@ pub(crate) async fn inner_start_profile_at( sketch_surface: SketchSurface, tag: Option, args: Args, -) -> Result, KclError> { +) -> Result { if let SketchSurface::Face(face) = &sketch_surface { // Flush the batch for our fillets/chamfers if there are any. // If we do not do these for sketch on face, things will fail with face does not exist. @@ -1324,12 +1324,12 @@ pub(crate) async fn inner_start_profile_at( }, start: current_path, }; - Ok(Box::new(sketch_group)) + Ok(sketch_group) } /// Returns the X component of the sketch profile start point. pub async fn profile_start_x(args: Args) -> Result { - let sketch_group: Box = args.get_sketch_group()?; + let sketch_group: SketchGroup = args.get_sketch_group()?; let x = inner_profile_start_x(sketch_group)?; args.make_user_val_from_f64(x) } @@ -1347,13 +1347,13 @@ pub async fn profile_start_x(args: Args) -> Result { #[stdlib { name = "profileStartX" }] -pub(crate) fn inner_profile_start_x(sketch_group: Box) -> Result { +pub(crate) fn inner_profile_start_x(sketch_group: SketchGroup) -> Result { Ok(sketch_group.start.to[0]) } /// Returns the Y component of the sketch profile start point. pub async fn profile_start_y(args: Args) -> Result { - let sketch_group: Box = args.get_sketch_group()?; + let sketch_group: SketchGroup = args.get_sketch_group()?; let x = inner_profile_start_y(sketch_group)?; args.make_user_val_from_f64(x) } @@ -1370,13 +1370,13 @@ pub async fn profile_start_y(args: Args) -> Result { #[stdlib { name = "profileStartY" }] -pub(crate) fn inner_profile_start_y(sketch_group: Box) -> Result { +pub(crate) fn inner_profile_start_y(sketch_group: SketchGroup) -> Result { Ok(sketch_group.start.to[1]) } /// Returns the sketch profile start point. pub async fn profile_start(args: Args) -> Result { - let sketch_group: Box = args.get_sketch_group()?; + let sketch_group: SketchGroup = args.get_sketch_group()?; let point = inner_profile_start(sketch_group)?; Ok(KclValue::UserVal(UserVal { value: serde_json::to_value(point).map_err(|e| { @@ -1404,17 +1404,17 @@ pub async fn profile_start(args: Args) -> Result { #[stdlib { name = "profileStart" }] -pub(crate) fn inner_profile_start(sketch_group: Box) -> Result<[f64; 2], KclError> { +pub(crate) fn inner_profile_start(sketch_group: SketchGroup) -> Result<[f64; 2], KclError> { Ok(sketch_group.start.to) } /// Close the current sketch. pub async fn close(args: Args) -> Result { - let (sketch_group, tag): (Box, Option) = args.get_sketch_group_and_optional_tag()?; + let (sketch_group, tag): (SketchGroup, Option) = args.get_sketch_group_and_optional_tag()?; let new_sketch_group = inner_close(sketch_group, tag, args).await?; - Ok(KclValue::SketchGroup(new_sketch_group)) + Ok(KclValue::new_user_val(new_sketch_group.meta.clone(), new_sketch_group)) } /// Construct a line segment from the current origin back to the profile's @@ -1442,10 +1442,10 @@ pub async fn close(args: Args) -> Result { name = "close", }] pub(crate) async fn inner_close( - sketch_group: Box, + sketch_group: SketchGroup, tag: Option, args: Args, -) -> Result, KclError> { +) -> Result { let from = sketch_group.current_pen_position()?; let to: Point2d = sketch_group.start.from.into(); @@ -1517,11 +1517,11 @@ pub enum ArcData { /// Draw an arc. pub async fn arc(args: Args) -> Result { - let (data, sketch_group, tag): (ArcData, Box, Option) = + let (data, sketch_group, tag): (ArcData, SketchGroup, Option) = args.get_data_and_sketch_group_and_tag()?; let new_sketch_group = inner_arc(data, sketch_group, tag, args).await?; - Ok(KclValue::SketchGroup(new_sketch_group)) + Ok(KclValue::new_user_val(new_sketch_group.meta.clone(), new_sketch_group)) } /// Starting at the current sketch's origin, draw a curved line segment along @@ -1553,10 +1553,10 @@ pub async fn arc(args: Args) -> Result { }] pub(crate) async fn inner_arc( data: ArcData, - sketch_group: Box, + sketch_group: SketchGroup, tag: Option, args: Args, -) -> Result, KclError> { +) -> Result { let from: Point2d = sketch_group.current_pen_position()?; let (center, angle_start, angle_end, radius, end) = match &data { @@ -1640,11 +1640,11 @@ pub enum TangentialArcData { /// Draw a tangential arc. pub async fn tangential_arc(args: Args) -> Result { - let (data, sketch_group, tag): (TangentialArcData, Box, Option) = + let (data, sketch_group, tag): (TangentialArcData, SketchGroup, Option) = args.get_data_and_sketch_group_and_tag()?; let new_sketch_group = inner_tangential_arc(data, sketch_group, tag, args).await?; - Ok(KclValue::SketchGroup(new_sketch_group)) + Ok(KclValue::new_user_val(new_sketch_group.meta.clone(), new_sketch_group)) } /// Starting at the current sketch's origin, draw a curved line segment along @@ -1676,10 +1676,10 @@ pub async fn tangential_arc(args: Args) -> Result { }] async fn inner_tangential_arc( data: TangentialArcData, - sketch_group: Box, + sketch_group: SketchGroup, tag: Option, args: Args, -) -> Result, KclError> { +) -> Result { let from: Point2d = sketch_group.current_pen_position()?; // next set of lines is some undocumented voodoo from get_tangential_arc_to_info let tangent_info = sketch_group.get_tangential_info_from_paths(); //this function desperately needs some documentation @@ -1793,7 +1793,7 @@ pub async fn tangential_arc_to(args: Args) -> Result { // Get arguments to function call let mut it = args.args.iter(); let to: [f64; 2] = get_arg(&mut it, src)?.get_json()?; - let sketch_group: Box = get_arg(&mut it, src)?.get_json()?; + let sketch_group: SketchGroup = get_arg(&mut it, src)?.get_json()?; let tag = if let Ok(memory_item) = get_arg(&mut it, src) { memory_item.get_json_opt()? } else { @@ -1801,7 +1801,7 @@ pub async fn tangential_arc_to(args: Args) -> Result { }; let new_sketch_group = inner_tangential_arc_to(to, sketch_group, tag, args).await?; - Ok(KclValue::SketchGroup(new_sketch_group)) + Ok(KclValue::new_user_val(new_sketch_group.meta.clone(), new_sketch_group)) } /// Starting at the current sketch's origin, draw a curved line segment along @@ -1826,10 +1826,10 @@ pub async fn tangential_arc_to(args: Args) -> Result { }] async fn inner_tangential_arc_to( to: [f64; 2], - sketch_group: Box, + sketch_group: SketchGroup, tag: Option, args: Args, -) -> Result, KclError> { +) -> Result { let from: Point2d = sketch_group.current_pen_position()?; let tangent_info = sketch_group.get_tangential_info_from_paths(); let tan_previous_point = if tangent_info.is_center { @@ -1888,11 +1888,11 @@ pub struct BezierData { /// Draw a bezier curve. pub async fn bezier_curve(args: Args) -> Result { - let (data, sketch_group, tag): (BezierData, Box, Option) = + let (data, sketch_group, tag): (BezierData, SketchGroup, Option) = args.get_data_and_sketch_group_and_tag()?; let new_sketch_group = inner_bezier_curve(data, sketch_group, tag, args).await?; - Ok(KclValue::SketchGroup(new_sketch_group)) + Ok(KclValue::new_user_val(new_sketch_group.meta.clone(), new_sketch_group)) } /// Draw a smooth, continuous, curved line segment from the current origin to @@ -1918,10 +1918,10 @@ pub async fn bezier_curve(args: Args) -> Result { }] async fn inner_bezier_curve( data: BezierData, - sketch_group: Box, + sketch_group: SketchGroup, tag: Option, args: Args, -) -> Result, KclError> { +) -> Result { let from = sketch_group.current_pen_position()?; let relative = true; @@ -1980,10 +1980,10 @@ async fn inner_bezier_curve( /// Use a sketch to cut a hole in another sketch. pub async fn hole(args: Args) -> Result { - let (hole_sketch_group, sketch_group): (SketchGroupSet, Box) = args.get_sketch_groups()?; + let (hole_sketch_group, sketch_group): (SketchGroupSet, SketchGroup) = args.get_sketch_groups()?; let new_sketch_group = inner_hole(hole_sketch_group, sketch_group, args).await?; - Ok(KclValue::SketchGroup(new_sketch_group)) + Ok(KclValue::new_user_val(new_sketch_group.meta.clone(), new_sketch_group)) } /// Use a 2-dimensional sketch to cut a hole in another 2-dimensional sketch. @@ -2022,10 +2022,10 @@ pub async fn hole(args: Args) -> Result { }] async fn inner_hole( hole_sketch_group: SketchGroupSet, - sketch_group: Box, + sketch_group: SketchGroup, args: Args, -) -> Result, KclError> { - let hole_sketch_groups: Vec> = hole_sketch_group.into(); +) -> Result { + let hole_sketch_groups: Vec = hole_sketch_group.into(); for hole_sketch_group in hole_sketch_groups { args.batch_modeling_cmd( uuid::Uuid::new_v4(), diff --git a/src/wasm-lib/tests/modify/main.rs b/src/wasm-lib/tests/modify/main.rs index fa7c0319c2..b075485ec0 100644 --- a/src/wasm-lib/tests/modify/main.rs +++ b/src/wasm-lib/tests/modify/main.rs @@ -1,7 +1,7 @@ use anyhow::Result; use kcl_lib::{ ast::{modify::modify_ast_for_sketch, types::Program}, - executor::{ExecutorContext, KclValue, PlaneType, SourceRange}, + executor::{ExecutorContext, KclValue, PlaneType, SketchGroup, SourceRange}, }; use kittycad::types::{ModelingCmd, Point3D}; use pretty_assertions::assert_eq; @@ -39,9 +39,12 @@ async fn setup(code: &str, name: &str) -> Result<(ExecutorContext, Program, uuid // We need to get the sketch ID. // Get the sketch group ID from memory. - let KclValue::SketchGroup(sketch_group) = memory.get(name, SourceRange::default()).unwrap() else { + let KclValue::UserVal(user_val) = memory.get(name, SourceRange::default()).unwrap() else { anyhow::bail!("part001 not found in memory: {:?}", memory); }; + let Some((sketch_group, _meta)) = user_val.get::() else { + anyhow::bail!("part001 was not a SketchGroup"); + }; let sketch_id = sketch_group.id; let plane_id = uuid::Uuid::new_v4();