diff --git a/src/lib/testHelpers.ts b/src/lib/testHelpers.ts index 041af6982..2e7a6f1d7 100644 --- a/src/lib/testHelpers.ts +++ b/src/lib/testHelpers.ts @@ -5,6 +5,9 @@ import { EngineCommand, } from '../lang/std/engineConnection' import { SourceRange } from 'lang/executor' +import { Models } from '@kittycad/lib' + +type WebSocketResponse = Models['OkWebSocketResponseData_type'] class MockEngineCommandManager { constructor(mockParams: { @@ -23,7 +26,13 @@ class MockEngineCommandManager { range: SourceRange command: EngineCommand }): Promise { - return Promise.resolve() + const response: WebSocketResponse = { + type: 'modeling', + data: { + modeling_response: { type: 'empty' }, + }, + } + return Promise.resolve(JSON.stringify(response)) } sendModelingCommandFromWasm( id: string, diff --git a/src/wasm-lib/Cargo.lock b/src/wasm-lib/Cargo.lock index 2ef7ef782..8b9590b09 100644 --- a/src/wasm-lib/Cargo.lock +++ b/src/wasm-lib/Cargo.lock @@ -148,6 +148,17 @@ dependencies = [ "thiserror", ] +[[package]] +name = "async-recursion" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fd55a5ba1179988837d24ab4c7cc8ed6efdeff578ede0416b4225a5fca35bd0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.37", +] + [[package]] name = "async-trait" version = "0.1.73" @@ -1376,9 +1387,10 @@ dependencies = [ [[package]] name = "kcl-lib" -version = "0.1.30" +version = "0.1.31" dependencies = [ "anyhow", + "async-recursion", "async-trait", "bson", "clap", diff --git a/src/wasm-lib/derive-docs/src/lib.rs b/src/wasm-lib/derive-docs/src/lib.rs index 4c85e3dd7..cd49f17d8 100644 --- a/src/wasm-lib/derive-docs/src/lib.rs +++ b/src/wasm-lib/derive-docs/src/lib.rs @@ -79,13 +79,6 @@ fn do_stdlib_inner( )); } - if ast.sig.asyncness.is_some() { - errors.push(Error::new_spanned( - &ast.sig.fn_token, - "stdlib functions must not be async", - )); - } - if ast.sig.unsafety.is_some() { errors.push(Error::new_spanned( &ast.sig.unsafety, @@ -118,6 +111,7 @@ fn do_stdlib_inner( let fn_name = &ast.sig.ident; let fn_name_str = fn_name.to_string().replace("inner_", ""); let fn_name_ident = format_ident!("{}", fn_name_str); + let boxed_fn_name_ident = format_ident!("boxed_{}", fn_name_str); let _visibility = &ast.vis; let (summary_text, description_text) = extract_doc_from_attrs(&ast.attrs); @@ -204,7 +198,10 @@ fn do_stdlib_inner( syn::FnArg::Typed(pat) => pat.ty.as_ref().into_token_stream(), }; - let ty_string = ty.to_string().replace('&', "").replace("mut", "").replace(' ', ""); + let mut ty_string = ty.to_string().replace('&', "").replace("mut", "").replace(' ', ""); + if ty_string.starts_with("Args") { + ty_string = "Args".to_string(); + } let ty_string = ty_string.trim().to_string(); let ty_ident = if ty_string.starts_with("Vec<") { let ty_string = ty_string.trim_start_matches("Vec<").trim_end_matches('>'); @@ -305,6 +302,14 @@ fn do_stdlib_inner( #description_doc_comment #const_struct + fn #boxed_fn_name_ident( + args: crate::std::Args, + ) -> std::pin::Pin< + Box>>, + > { + Box::pin(#fn_name_ident(args)) + } + impl #docs_crate::StdLibFn for #name_ident { fn name(&self) -> String { @@ -348,7 +353,7 @@ fn do_stdlib_inner( } fn std_lib_fn(&self) -> crate::std::StdFn { - #fn_name_ident + #boxed_fn_name_ident } fn clone_box(&self) -> Box { diff --git a/src/wasm-lib/derive-docs/tests/box.gen b/src/wasm-lib/derive-docs/tests/box.gen index 4a7257208..a21f0ca0f 100644 --- a/src/wasm-lib/derive-docs/tests/box.gen +++ b/src/wasm-lib/derive-docs/tests/box.gen @@ -7,6 +7,18 @@ pub(crate) struct Show {} #[allow(non_upper_case_globals, missing_docs)] #[doc = "Std lib function: show"] pub(crate) const Show: Show = Show {}; +fn boxed_show( + args: crate::std::Args, +) -> std::pin::Pin< + Box< + dyn std::future::Future< + Output = anyhow::Result, + >, + >, +> { + Box::pin(show(args)) +} + impl crate::docs::StdLibFn for Show { fn name(&self) -> String { "show".to_string() @@ -57,7 +69,7 @@ impl crate::docs::StdLibFn for Show { } fn std_lib_fn(&self) -> crate::std::StdFn { - show + boxed_show } fn clone_box(&self) -> Box { diff --git a/src/wasm-lib/derive-docs/tests/lineTo.gen b/src/wasm-lib/derive-docs/tests/lineTo.gen index 89f5c0125..6d2e34f4a 100644 --- a/src/wasm-lib/derive-docs/tests/lineTo.gen +++ b/src/wasm-lib/derive-docs/tests/lineTo.gen @@ -7,6 +7,18 @@ pub(crate) struct LineTo {} #[allow(non_upper_case_globals, missing_docs)] #[doc = "Std lib function: lineTo"] pub(crate) const LineTo: LineTo = LineTo {}; +fn boxed_line_to( + args: crate::std::Args, +) -> std::pin::Pin< + Box< + dyn std::future::Future< + Output = anyhow::Result, + >, + >, +> { + Box::pin(line_to(args)) +} + impl crate::docs::StdLibFn for LineTo { fn name(&self) -> String { "lineTo".to_string() @@ -65,7 +77,7 @@ impl crate::docs::StdLibFn for LineTo { } fn std_lib_fn(&self) -> crate::std::StdFn { - line_to + boxed_line_to } fn clone_box(&self) -> Box { diff --git a/src/wasm-lib/derive-docs/tests/min.gen b/src/wasm-lib/derive-docs/tests/min.gen index a848af258..d9b393efd 100644 --- a/src/wasm-lib/derive-docs/tests/min.gen +++ b/src/wasm-lib/derive-docs/tests/min.gen @@ -7,6 +7,18 @@ pub(crate) struct Min {} #[allow(non_upper_case_globals, missing_docs)] #[doc = "Std lib function: min"] pub(crate) const Min: Min = Min {}; +fn boxed_min( + args: crate::std::Args, +) -> std::pin::Pin< + Box< + dyn std::future::Future< + Output = anyhow::Result, + >, + >, +> { + Box::pin(min(args)) +} + impl crate::docs::StdLibFn for Min { fn name(&self) -> String { "min".to_string() @@ -57,7 +69,7 @@ impl crate::docs::StdLibFn for Min { } fn std_lib_fn(&self) -> crate::std::StdFn { - min + boxed_min } fn clone_box(&self) -> Box { diff --git a/src/wasm-lib/derive-docs/tests/show.gen b/src/wasm-lib/derive-docs/tests/show.gen index 7692ddd9d..0d2538429 100644 --- a/src/wasm-lib/derive-docs/tests/show.gen +++ b/src/wasm-lib/derive-docs/tests/show.gen @@ -7,6 +7,18 @@ pub(crate) struct Show {} #[allow(non_upper_case_globals, missing_docs)] #[doc = "Std lib function: show"] pub(crate) const Show: Show = Show {}; +fn boxed_show( + args: crate::std::Args, +) -> std::pin::Pin< + Box< + dyn std::future::Future< + Output = anyhow::Result, + >, + >, +> { + Box::pin(show(args)) +} + impl crate::docs::StdLibFn for Show { fn name(&self) -> String { "show".to_string() @@ -52,7 +64,7 @@ impl crate::docs::StdLibFn for Show { } fn std_lib_fn(&self) -> crate::std::StdFn { - show + boxed_show } fn clone_box(&self) -> Box { diff --git a/src/wasm-lib/kcl/Cargo.toml b/src/wasm-lib/kcl/Cargo.toml index 3922eb20b..baa2818ea 100644 --- a/src/wasm-lib/kcl/Cargo.toml +++ b/src/wasm-lib/kcl/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "kcl-lib" description = "KittyCAD Language" -version = "0.1.30" +version = "0.1.31" edition = "2021" license = "MIT" @@ -9,6 +9,7 @@ license = "MIT" [dependencies] anyhow = { version = "1.0.75", features = ["backtrace"] } +async-recursion = "1.0.5" async-trait = "0.1.73" clap = { version = "4.4.3", features = ["cargo", "derive", "env", "unicode"], optional = true } dashmap = "5.5.3" diff --git a/src/wasm-lib/kcl/src/ast/modify.rs b/src/wasm-lib/kcl/src/ast/modify.rs index 8df35bf4d..80eaf3547 100644 --- a/src/wasm-lib/kcl/src/ast/modify.rs +++ b/src/wasm-lib/kcl/src/ast/modify.rs @@ -71,7 +71,7 @@ pub async fn modify_ast_for_sketch( // Let's get the path info. let resp = engine - .send_modeling_cmd_get_response( + .send_modeling_cmd( uuid::Uuid::new_v4(), SourceRange::default(), ModelingCmd::PathGetInfo { path_id: sketch_id }, @@ -88,47 +88,6 @@ pub async fn modify_ast_for_sketch( })); }; - /* // Let's try to get the children of the sketch. - let resp = engine - .send_modeling_cmd_get_response( - uuid::Uuid::new_v4(), - SourceRange::default(), - ModelingCmd::EntityGetAllChildUuids { entity_id: sketch_id }, - ) - .await?; - let kittycad::types::OkWebSocketResponseData::Modeling { - modeling_response: kittycad::types::OkModelingCmdResponse::EntityGetAllChildUuids { data: children_info }, - } = &resp - else { - return Err(KclError::Engine(KclErrorDetails { - message: format!("Get child info response was not as expected: {:?}", resp), - source_ranges: vec![SourceRange::default()], - })); - }; - - println!("children_info: {:#?}", children_info); - - // Let's try to get the parent id. - let resp = engine - .send_modeling_cmd_get_response( - uuid::Uuid::new_v4(), - SourceRange::default(), - ModelingCmd::EntityGetParentId { entity_id: sketch_id }, - ) - .await?; - - let kittycad::types::OkWebSocketResponseData::Modeling { - modeling_response: kittycad::types::OkModelingCmdResponse::EntityGetParentId { data: parent_info }, - } = &resp - else { - return Err(KclError::Engine(KclErrorDetails { - message: format!("Get parent id response was not as expected: {:?}", resp), - source_ranges: vec![SourceRange::default()], - })); - }; - - println!("parent_info: {:#?}", parent_info);*/ - // Now let's get the control points for all the segments. // TODO: We should probably await all these at once so we aren't going one by one. // But I guess this is fine for now. @@ -136,7 +95,7 @@ pub async fn modify_ast_for_sketch( let mut control_points = Vec::new(); for segment in &path_info.segments { if let Some(command_id) = &segment.command_id { - let h = engine.send_modeling_cmd_get_response( + let h = engine.send_modeling_cmd( uuid::Uuid::new_v4(), SourceRange::default(), ModelingCmd::CurveGetControlPoints { curve_id: *command_id }, diff --git a/src/wasm-lib/kcl/src/ast/types.rs b/src/wasm-lib/kcl/src/ast/types.rs index cad4e174e..4eebcb748 100644 --- a/src/wasm-lib/kcl/src/ast/types.rs +++ b/src/wasm-lib/kcl/src/ast/types.rs @@ -571,11 +571,12 @@ impl BinaryPart { } } - pub fn get_result( + #[async_recursion::async_recursion(?Send)] + pub async fn get_result( &self, memory: &mut ProgramMemory, pipe_info: &mut PipeInfo, - engine: &mut EngineConnection, + engine: &EngineConnection, ) -> Result { // We DO NOT set this gloablly because if we did and this was called inside a pipe it would // stop the execution of the pipe. @@ -590,11 +591,13 @@ impl BinaryPart { Ok(value.clone()) } BinaryPart::BinaryExpression(binary_expression) => { - binary_expression.get_result(memory, &mut new_pipe_info, engine) + binary_expression.get_result(memory, &mut new_pipe_info, engine).await + } + BinaryPart::CallExpression(call_expression) => { + call_expression.execute(memory, &mut new_pipe_info, engine).await } - BinaryPart::CallExpression(call_expression) => call_expression.execute(memory, &mut new_pipe_info, engine), BinaryPart::UnaryExpression(unary_expression) => { - unary_expression.get_result(memory, &mut new_pipe_info, engine) + unary_expression.get_result(memory, &mut new_pipe_info, engine).await } BinaryPart::MemberExpression(member_expression) => member_expression.get_result(memory), } @@ -810,11 +813,12 @@ impl CallExpression { ) } - pub fn execute( + #[async_recursion::async_recursion(?Send)] + pub async fn execute( &self, memory: &mut ProgramMemory, pipe_info: &mut PipeInfo, - engine: &mut EngineConnection, + engine: &EngineConnection, ) -> Result { let fn_name = self.callee.name.clone(); @@ -828,7 +832,7 @@ impl CallExpression { value.clone() } Value::BinaryExpression(binary_expression) => { - binary_expression.get_result(memory, pipe_info, engine)? + binary_expression.get_result(memory, pipe_info, engine).await? } Value::CallExpression(call_expression) => { // We DO NOT set this gloablly because if we did and this was called inside a pipe it would @@ -836,11 +840,15 @@ impl CallExpression { // THIS IS IMPORTANT. let mut new_pipe_info = pipe_info.clone(); new_pipe_info.is_in_pipe = false; - call_expression.execute(memory, &mut new_pipe_info, engine)? + call_expression.execute(memory, &mut new_pipe_info, engine).await? } - Value::UnaryExpression(unary_expression) => unary_expression.get_result(memory, pipe_info, engine)?, - Value::ObjectExpression(object_expression) => object_expression.execute(memory, pipe_info, engine)?, - Value::ArrayExpression(array_expression) => array_expression.execute(memory, pipe_info, engine)?, + Value::UnaryExpression(unary_expression) => { + unary_expression.get_result(memory, pipe_info, engine).await? + } + Value::ObjectExpression(object_expression) => { + object_expression.execute(memory, pipe_info, engine).await? + } + Value::ArrayExpression(array_expression) => array_expression.execute(memory, pipe_info, engine).await?, Value::PipeExpression(pipe_expression) => { return Err(KclError::Semantic(KclErrorDetails { message: format!("PipeExpression not implemented here: {:?}", pipe_expression), @@ -877,25 +885,27 @@ impl CallExpression { fn_name, source_range, fn_args );*/ // Attempt to call the function. - let mut args = crate::std::Args::new(fn_args, self.into(), engine); - let result = func.std_lib_fn()(&mut args)?; + let args = crate::std::Args::new(fn_args, self.into(), engine.clone()); + let result = func.std_lib_fn()(args).await?; if pipe_info.is_in_pipe { pipe_info.index += 1; pipe_info.previous_results.push(result); - execute_pipe_body(memory, &pipe_info.body.clone(), pipe_info, self.into(), engine) + execute_pipe_body(memory, &pipe_info.body.clone(), pipe_info, self.into(), engine).await } else { Ok(result) } } Function::InMemory => { - let mem = memory.clone(); - let func = mem.get(&fn_name, self.into())?; - let result = func.call_fn(&fn_args, &mem, engine)?.ok_or_else(|| { - KclError::UndefinedValue(KclErrorDetails { - message: format!("Result of function {} is undefined", fn_name), - source_ranges: vec![self.into()], - }) - })?; + let func = memory.get(&fn_name, self.into())?; + let result = func + .call_fn(fn_args, memory.clone(), engine.clone()) + .await? + .ok_or_else(|| { + KclError::UndefinedValue(KclErrorDetails { + message: format!("Result of function {} is undefined", fn_name), + source_ranges: vec![self.into()], + }) + })?; let result = result.get_value()?; @@ -903,7 +913,7 @@ impl CallExpression { pipe_info.index += 1; pipe_info.previous_results.push(result); - execute_pipe_body(memory, &pipe_info.body.clone(), pipe_info, self.into(), engine) + execute_pipe_body(memory, &pipe_info.body.clone(), pipe_info, self.into(), engine).await } else { Ok(result) } @@ -1424,11 +1434,12 @@ impl ArrayExpression { None } - pub fn execute( + #[async_recursion::async_recursion(?Send)] + pub async fn execute( &self, memory: &mut ProgramMemory, pipe_info: &mut PipeInfo, - engine: &mut EngineConnection, + engine: &EngineConnection, ) -> Result { let mut results = Vec::with_capacity(self.elements.len()); @@ -1440,7 +1451,7 @@ impl ArrayExpression { value.clone() } Value::BinaryExpression(binary_expression) => { - binary_expression.get_result(memory, pipe_info, engine)? + binary_expression.get_result(memory, pipe_info, engine).await? } Value::CallExpression(call_expression) => { // We DO NOT set this gloablly because if we did and this was called inside a pipe it would @@ -1448,12 +1459,16 @@ impl ArrayExpression { // THIS IS IMPORTANT. let mut new_pipe_info = pipe_info.clone(); new_pipe_info.is_in_pipe = false; - call_expression.execute(memory, &mut new_pipe_info, engine)? + call_expression.execute(memory, &mut new_pipe_info, engine).await? } - Value::UnaryExpression(unary_expression) => unary_expression.get_result(memory, pipe_info, engine)?, - Value::ObjectExpression(object_expression) => object_expression.execute(memory, pipe_info, engine)?, - Value::ArrayExpression(array_expression) => array_expression.execute(memory, pipe_info, engine)?, - Value::PipeExpression(pipe_expression) => pipe_expression.get_result(memory, pipe_info, engine)?, + Value::UnaryExpression(unary_expression) => { + unary_expression.get_result(memory, pipe_info, engine).await? + } + Value::ObjectExpression(object_expression) => { + object_expression.execute(memory, pipe_info, engine).await? + } + Value::ArrayExpression(array_expression) => array_expression.execute(memory, pipe_info, engine).await?, + Value::PipeExpression(pipe_expression) => pipe_expression.get_result(memory, pipe_info, engine).await?, Value::PipeSubstitution(pipe_substitution) => { return Err(KclError::Semantic(KclErrorDetails { message: format!("PipeSubstitution not implemented here: {:?}", pipe_substitution), @@ -1569,11 +1584,12 @@ impl ObjectExpression { None } - pub fn execute( + #[async_recursion::async_recursion(?Send)] + pub async fn execute( &self, memory: &mut ProgramMemory, pipe_info: &mut PipeInfo, - engine: &mut EngineConnection, + engine: &EngineConnection, ) -> Result { let mut object = Map::new(); for property in &self.properties { @@ -1584,7 +1600,7 @@ impl ObjectExpression { value.clone() } Value::BinaryExpression(binary_expression) => { - binary_expression.get_result(memory, pipe_info, engine)? + binary_expression.get_result(memory, pipe_info, engine).await? } Value::CallExpression(call_expression) => { // We DO NOT set this gloablly because if we did and this was called inside a pipe it would @@ -1592,12 +1608,16 @@ impl ObjectExpression { // THIS IS IMPORTANT. let mut new_pipe_info = pipe_info.clone(); new_pipe_info.is_in_pipe = false; - call_expression.execute(memory, &mut new_pipe_info, engine)? + call_expression.execute(memory, &mut new_pipe_info, engine).await? } - Value::UnaryExpression(unary_expression) => unary_expression.get_result(memory, pipe_info, engine)?, - Value::ObjectExpression(object_expression) => object_expression.execute(memory, pipe_info, engine)?, - Value::ArrayExpression(array_expression) => array_expression.execute(memory, pipe_info, engine)?, - Value::PipeExpression(pipe_expression) => pipe_expression.get_result(memory, pipe_info, engine)?, + Value::UnaryExpression(unary_expression) => { + unary_expression.get_result(memory, pipe_info, engine).await? + } + Value::ObjectExpression(object_expression) => { + object_expression.execute(memory, pipe_info, engine).await? + } + Value::ArrayExpression(array_expression) => array_expression.execute(memory, pipe_info, engine).await?, + Value::PipeExpression(pipe_expression) => pipe_expression.get_result(memory, pipe_info, engine).await?, Value::PipeSubstitution(pipe_substitution) => { return Err(KclError::Semantic(KclErrorDetails { message: format!("PipeSubstitution not implemented here: {:?}", pipe_substitution), @@ -2005,11 +2025,12 @@ impl BinaryExpression { None } - pub fn get_result( + #[async_recursion::async_recursion(?Send)] + pub async fn get_result( &self, memory: &mut ProgramMemory, pipe_info: &mut PipeInfo, - engine: &mut EngineConnection, + engine: &EngineConnection, ) -> Result { // We DO NOT set this gloablly because if we did and this was called inside a pipe it would // stop the execution of the pipe. @@ -2019,11 +2040,13 @@ impl BinaryExpression { let left_json_value = self .left - .get_result(memory, &mut new_pipe_info, engine)? + .get_result(memory, &mut new_pipe_info, engine) + .await? .get_json_value()?; let right_json_value = self .right - .get_result(memory, &mut new_pipe_info, engine)? + .get_result(memory, &mut new_pipe_info, engine) + .await? .get_json_value()?; // First check if we are doing string concatenation. @@ -2173,11 +2196,11 @@ impl UnaryExpression { format!("{}{}", &self.operator, self.argument.recast(options, 0)) } - pub fn get_result( + pub async fn get_result( &self, memory: &mut ProgramMemory, pipe_info: &mut PipeInfo, - engine: &mut EngineConnection, + engine: &EngineConnection, ) -> Result { // We DO NOT set this gloablly because if we did and this was called inside a pipe it would // stop the execution of the pipe. @@ -2188,7 +2211,8 @@ impl UnaryExpression { let num = parse_json_number_as_f64( &self .argument - .get_result(memory, &mut new_pipe_info, engine)? + .get_result(memory, &mut new_pipe_info, engine) + .await? .get_json_value()?, self.into(), )?; @@ -2310,16 +2334,16 @@ impl PipeExpression { None } - pub fn get_result( + pub async fn get_result( &self, memory: &mut ProgramMemory, pipe_info: &mut PipeInfo, - engine: &mut EngineConnection, + engine: &EngineConnection, ) -> Result { // Reset the previous results. pipe_info.previous_results = vec![]; pipe_info.index = 0; - execute_pipe_body(memory, &self.body, pipe_info, self.into(), engine) + execute_pipe_body(memory, &self.body, pipe_info, self.into(), engine).await } /// Rename all identifiers that have the old name to the new given name. @@ -2330,12 +2354,13 @@ impl PipeExpression { } } -fn execute_pipe_body( +#[async_recursion::async_recursion(?Send)] +async fn execute_pipe_body( memory: &mut ProgramMemory, body: &[Value], pipe_info: &mut PipeInfo, source_range: SourceRange, - engine: &mut EngineConnection, + engine: &EngineConnection, ) -> Result { if pipe_info.index == body.len() { pipe_info.is_in_pipe = false; @@ -2360,15 +2385,15 @@ fn execute_pipe_body( match expression { Value::BinaryExpression(binary_expression) => { - let result = binary_expression.get_result(memory, pipe_info, engine)?; + let result = binary_expression.get_result(memory, pipe_info, engine).await?; pipe_info.previous_results.push(result); pipe_info.index += 1; - execute_pipe_body(memory, body, pipe_info, source_range, engine) + execute_pipe_body(memory, body, pipe_info, source_range, engine).await } Value::CallExpression(call_expression) => { pipe_info.is_in_pipe = true; pipe_info.body = body.to_vec(); - call_expression.execute(memory, pipe_info, engine) + call_expression.execute(memory, pipe_info, engine).await } _ => { // Return an error this should not happen. diff --git a/src/wasm-lib/kcl/src/engine/conn.rs b/src/wasm-lib/kcl/src/engine/conn.rs index 1f581d527..baca66b9c 100644 --- a/src/wasm-lib/kcl/src/engine/conn.rs +++ b/src/wasm-lib/kcl/src/engine/conn.rs @@ -17,17 +17,11 @@ use crate::{ type WebSocketTcpWrite = futures::stream::SplitSink, WsMsg>; #[derive(Debug, Clone)] +#[allow(dead_code)] // for the TcpReadHandle pub struct EngineConnection { engine_req_tx: mpsc::Sender, - tcp_read_handle: Arc>>, responses: Arc>, -} - -impl Drop for EngineConnection { - fn drop(&mut self) { - // Drop the read handle. - self.tcp_read_handle.abort(); - } + tcp_read_handle: Arc, } pub struct TcpRead { @@ -48,6 +42,18 @@ impl TcpRead { } } +#[derive(Debug)] +pub struct TcpReadHandle { + handle: Arc>>, +} + +impl Drop for TcpReadHandle { + fn drop(&mut self) { + // Drop the read handle. + self.handle.abort(); + } +} + /// Requests to send to the engine, and a way to await a response. struct ToEngineReq { /// The request to send @@ -114,7 +120,9 @@ impl EngineConnection { Ok(EngineConnection { engine_req_tx, - tcp_read_handle: Arc::new(tcp_read_handle), + tcp_read_handle: Arc::new(TcpReadHandle { + handle: Arc::new(tcp_read_handle), + }), responses, }) } @@ -122,20 +130,7 @@ impl EngineConnection { #[async_trait::async_trait(?Send)] impl EngineManager for EngineConnection { - /// Send a modeling command. - /// Do not wait for the response message. - fn send_modeling_cmd( - &self, - id: uuid::Uuid, - source_range: crate::executor::SourceRange, - cmd: kittycad::types::ModelingCmd, - ) -> Result<(), KclError> { - futures::executor::block_on(self.send_modeling_cmd_get_response(id, source_range, cmd))?; - Ok(()) - } - - /// Send a modeling command and wait for the response message. - async fn send_modeling_cmd_get_response( + async fn send_modeling_cmd( &self, id: uuid::Uuid, source_range: crate::executor::SourceRange, @@ -146,7 +141,10 @@ impl EngineManager for EngineConnection { // Send the request to the engine, via the actor. self.engine_req_tx .send(ToEngineReq { - req: WebSocketRequest::ModelingCmdReq { cmd, cmd_id: id }, + req: WebSocketRequest::ModelingCmdReq { + cmd: cmd.clone(), + cmd_id: id, + }, request_sent: tx, }) .await @@ -173,8 +171,10 @@ impl EngineManager for EngineConnection { })?; // Wait for the response. - loop { - if let Some(resp) = self.responses.get(&id) { + let current_time = std::time::Instant::now(); + while current_time.elapsed().as_secs() < 60 { + // We pop off the responses to cleanup our mappings. + if let Some((_, resp)) = self.responses.remove(&id) { return if let Some(data) = &resp.resp { Ok(data.clone()) } else { @@ -185,5 +185,10 @@ impl EngineManager for EngineConnection { }; } } + + Err(KclError::Engine(KclErrorDetails { + message: format!("Modeling command timed out `{}`: {:?}", id, cmd), + source_ranges: vec![source_range], + })) } } diff --git a/src/wasm-lib/kcl/src/engine/conn_mock.rs b/src/wasm-lib/kcl/src/engine/conn_mock.rs index ff06a388c..b1dc6c1bd 100644 --- a/src/wasm-lib/kcl/src/engine/conn_mock.rs +++ b/src/wasm-lib/kcl/src/engine/conn_mock.rs @@ -17,21 +17,14 @@ impl EngineConnection { #[async_trait::async_trait(?Send)] impl crate::engine::EngineManager for EngineConnection { - fn send_modeling_cmd( - &self, - _id: uuid::Uuid, - _source_range: crate::executor::SourceRange, - _cmd: kittycad::types::ModelingCmd, - ) -> Result<(), KclError> { - Ok(()) - } - - async fn send_modeling_cmd_get_response( + async fn send_modeling_cmd( &self, _id: uuid::Uuid, _source_range: crate::executor::SourceRange, _cmd: kittycad::types::ModelingCmd, ) -> Result { - todo!() + Ok(OkWebSocketResponseData::Modeling { + modeling_response: kittycad::types::OkModelingCmdResponse::Empty {}, + }) } } diff --git a/src/wasm-lib/kcl/src/engine/conn_wasm.rs b/src/wasm-lib/kcl/src/engine/conn_wasm.rs index c7b91ae08..0adefa0c1 100644 --- a/src/wasm-lib/kcl/src/engine/conn_wasm.rs +++ b/src/wasm-lib/kcl/src/engine/conn_wasm.rs @@ -1,5 +1,6 @@ //! Functions for setting up our WebSocket and WebRTC connections for communications with the //! engine. +use std::sync::Arc; use anyhow::Result; use kittycad::types::WebSocketRequest; @@ -23,43 +24,20 @@ extern "C" { #[derive(Debug, Clone)] pub struct EngineConnection { - manager: EngineCommandManager, + manager: Arc, } impl EngineConnection { pub async fn new(manager: EngineCommandManager) -> Result { - Ok(EngineConnection { manager }) + Ok(EngineConnection { + manager: Arc::new(manager), + }) } } #[async_trait::async_trait(?Send)] impl crate::engine::EngineManager for EngineConnection { - fn send_modeling_cmd( - &self, - id: uuid::Uuid, - source_range: crate::executor::SourceRange, - cmd: kittycad::types::ModelingCmd, - ) -> Result<(), KclError> { - let source_range_str = serde_json::to_string(&source_range).map_err(|e| { - KclError::Engine(KclErrorDetails { - message: format!("Failed to serialize source range: {:?}", e), - source_ranges: vec![source_range], - }) - })?; - let ws_msg = WebSocketRequest::ModelingCmdReq { cmd, cmd_id: id }; - let cmd_str = serde_json::to_string(&ws_msg).map_err(|e| { - KclError::Engine(KclErrorDetails { - message: format!("Failed to serialize modeling command: {:?}", e), - source_ranges: vec![source_range], - }) - })?; - let _ = self - .manager - .sendModelingCommandFromWasm(id.to_string(), source_range_str, cmd_str); - Ok(()) - } - - async fn send_modeling_cmd_get_response( + async fn send_modeling_cmd( &self, id: uuid::Uuid, source_range: crate::executor::SourceRange, diff --git a/src/wasm-lib/kcl/src/engine/mod.rs b/src/wasm-lib/kcl/src/engine/mod.rs index 9806ff9c5..fdfd43c2d 100644 --- a/src/wasm-lib/kcl/src/engine/mod.rs +++ b/src/wasm-lib/kcl/src/engine/mod.rs @@ -33,17 +33,8 @@ pub use conn_mock::EngineConnection; #[async_trait::async_trait(?Send)] pub trait EngineManager: Clone { - /// Send a modeling command. - /// Do not wait for the response message. - fn send_modeling_cmd( - &self, - id: uuid::Uuid, - source_range: crate::executor::SourceRange, - cmd: kittycad::types::ModelingCmd, - ) -> Result<(), crate::errors::KclError>; - /// Send a modeling command and wait for the response message. - async fn send_modeling_cmd_get_response( + async fn send_modeling_cmd( &self, id: uuid::Uuid, source_range: crate::executor::SourceRange, diff --git a/src/wasm-lib/kcl/src/executor.rs b/src/wasm-lib/kcl/src/executor.rs index 44484da8f..eb5037040 100644 --- a/src/wasm-lib/kcl/src/executor.rs +++ b/src/wasm-lib/kcl/src/executor.rs @@ -104,7 +104,7 @@ pub enum MemoryItem { SketchGroup(Box), ExtrudeGroup(Box), #[ts(skip)] - ExtrudeTransform(ExtrudeTransform), + ExtrudeTransform(Box), #[ts(skip)] Function { #[serde(skip)] @@ -134,13 +134,28 @@ pub struct ExtrudeTransform { pub meta: Vec, } -pub type MemoryFunction = fn( - s: &[MemoryItem], - memory: &ProgramMemory, - expression: &FunctionExpression, - metadata: &[Metadata], - engine: &mut EngineConnection, -) -> Result, KclError>; +pub type MemoryFunction = + fn( + s: Vec, + memory: ProgramMemory, + expression: Box, + metadata: Vec, + engine: EngineConnection, + ) -> std::pin::Pin, KclError>>>>; + +fn force_memory_function< + F: Fn( + Vec, + ProgramMemory, + Box, + Vec, + EngineConnection, + ) -> std::pin::Pin, KclError>>>>, +>( + f: F, +) -> F { + f +} impl From for Vec { fn from(item: MemoryItem) -> Self { @@ -168,24 +183,24 @@ impl MemoryItem { } } - pub fn call_fn( + pub async fn call_fn( &self, - args: &[MemoryItem], - memory: &ProgramMemory, - engine: &mut EngineConnection, + args: Vec, + memory: ProgramMemory, + engine: EngineConnection, ) -> Result, KclError> { - if let MemoryItem::Function { func, expression, meta } = self { + if let MemoryItem::Function { func, expression, meta } = &self { if let Some(func) = func { - func(args, memory, expression, meta, engine) + func(args, memory, expression.clone(), meta.clone(), engine).await } else { Err(KclError::Semantic(KclErrorDetails { - message: format!("Not a function: {:?}", self), + message: format!("Not a function: {:?}", expression), source_ranges: vec![], })) } } else { Err(KclError::Semantic(KclErrorDetails { - message: format!("not a function: {:?}", self), + message: "not a in memory function".to_string(), source_ranges: vec![], })) } @@ -579,11 +594,11 @@ impl Default for PipeInfo { } /// Execute a AST's program. -pub fn execute( +pub async fn execute( program: crate::ast::types::Program, memory: &mut ProgramMemory, options: BodyType, - engine: &mut EngineConnection, + engine: &EngineConnection, ) -> Result { let mut pipe_info = PipeInfo::default(); @@ -602,7 +617,7 @@ pub fn execute( args.push(memory_item.clone()); } Value::CallExpression(call_expr) => { - let result = call_expr.execute(memory, &mut pipe_info, engine)?; + let result = call_expr.execute(memory, &mut pipe_info, engine).await?; args.push(result); } // We do nothing for the rest. @@ -620,7 +635,7 @@ pub fn execute( memory.return_ = Some(ProgramReturn::Arguments(call_expr.arguments.clone())); } else if let Some(func) = memory.clone().root.get(&fn_name) { - let result = func.call_fn(&args, memory, engine)?; + let result = func.call_fn(args.clone(), memory.clone(), engine.clone()).await?; memory.return_ = result; } else { @@ -646,22 +661,27 @@ pub fn execute( memory.add(&var_name, value.clone(), source_range)?; } Value::BinaryExpression(binary_expression) => { - let result = binary_expression.get_result(memory, &mut pipe_info, engine)?; + let result = binary_expression.get_result(memory, &mut pipe_info, engine).await?; memory.add(&var_name, result, source_range)?; } Value::FunctionExpression(function_expression) => { - memory.add( - &var_name, - MemoryItem::Function{ - expression: function_expression.clone(), - meta: vec![metadata], - func: Some(|args: &[MemoryItem], memory: &ProgramMemory, function_expression: &FunctionExpression, _metadata: &[Metadata], engine: &mut EngineConnection| -> Result, KclError> { + let mem_func = force_memory_function( + |args: Vec, + memory: ProgramMemory, + function_expression: Box, + _metadata: Vec, + engine: EngineConnection| { + Box::pin(async move { let mut fn_memory = memory.clone(); if args.len() != function_expression.params.len() { return Err(KclError::Semantic(KclErrorDetails { - message: format!("Expected {} arguments, got {}", function_expression.params.len(), args.len()), - source_ranges: vec![function_expression.into()], + message: format!( + "Expected {} arguments, got {}", + function_expression.params.len(), + args.len() + ), + source_ranges: vec![(&function_expression).into()], })); } @@ -674,20 +694,34 @@ pub fn execute( )?; } - let result = execute(function_expression.body.clone(), &mut fn_memory, BodyType::Block, engine)?; + let result = execute( + function_expression.body.clone(), + &mut fn_memory, + BodyType::Block, + &engine, + ) + .await?; Ok(result.return_) }) }, + ); + memory.add( + &var_name, + MemoryItem::Function { + expression: function_expression.clone(), + meta: vec![metadata], + func: Some(mem_func), + }, source_range, )?; } Value::CallExpression(call_expression) => { - let result = call_expression.execute(memory, &mut pipe_info, engine)?; + let result = call_expression.execute(memory, &mut pipe_info, engine).await?; memory.add(&var_name, result, source_range)?; } Value::PipeExpression(pipe_expression) => { - let result = pipe_expression.get_result(memory, &mut pipe_info, engine)?; + let result = pipe_expression.get_result(memory, &mut pipe_info, engine).await?; memory.add(&var_name, result, source_range)?; } Value::PipeSubstitution(pipe_substitution) => { @@ -700,11 +734,11 @@ pub fn execute( })); } Value::ArrayExpression(array_expression) => { - let result = array_expression.execute(memory, &mut pipe_info, engine)?; + let result = array_expression.execute(memory, &mut pipe_info, engine).await?; memory.add(&var_name, result, source_range)?; } Value::ObjectExpression(object_expression) => { - let result = object_expression.execute(memory, &mut pipe_info, engine)?; + let result = object_expression.execute(memory, &mut pipe_info, engine).await?; memory.add(&var_name, result, source_range)?; } Value::MemberExpression(member_expression) => { @@ -712,7 +746,7 @@ pub fn execute( memory.add(&var_name, result, source_range)?; } Value::UnaryExpression(unary_expression) => { - let result = unary_expression.get_result(memory, &mut pipe_info, engine)?; + let result = unary_expression.get_result(memory, &mut pipe_info, engine).await?; memory.add(&var_name, result, source_range)?; } } @@ -720,11 +754,11 @@ pub fn execute( } BodyItem::ReturnStatement(return_statement) => match &return_statement.argument { Value::BinaryExpression(bin_expr) => { - let result = bin_expr.get_result(memory, &mut pipe_info, engine)?; + let result = bin_expr.get_result(memory, &mut pipe_info, engine).await?; memory.return_ = Some(ProgramReturn::Value(result)); } Value::UnaryExpression(unary_expr) => { - let result = unary_expr.get_result(memory, &mut pipe_info, engine)?; + let result = unary_expr.get_result(memory, &mut pipe_info, engine).await?; memory.return_ = Some(ProgramReturn::Value(result)); } Value::Identifier(identifier) => { @@ -735,15 +769,15 @@ pub fn execute( memory.return_ = Some(ProgramReturn::Value(literal.into())); } Value::ArrayExpression(array_expr) => { - let result = array_expr.execute(memory, &mut pipe_info, engine)?; + let result = array_expr.execute(memory, &mut pipe_info, engine).await?; memory.return_ = Some(ProgramReturn::Value(result)); } Value::ObjectExpression(obj_expr) => { - let result = obj_expr.execute(memory, &mut pipe_info, engine)?; + let result = obj_expr.execute(memory, &mut pipe_info, engine).await?; memory.return_ = Some(ProgramReturn::Value(result)); } Value::CallExpression(call_expr) => { - let result = call_expr.execute(memory, &mut pipe_info, engine)?; + let result = call_expr.execute(memory, &mut pipe_info, engine).await?; memory.return_ = Some(ProgramReturn::Value(result)); } Value::MemberExpression(member_expr) => { @@ -751,7 +785,7 @@ pub fn execute( memory.return_ = Some(ProgramReturn::Value(result)); } Value::PipeExpression(pipe_expr) => { - let result = pipe_expr.get_result(memory, &mut pipe_info, engine)?; + let result = pipe_expr.get_result(memory, &mut pipe_info, engine).await?; memory.return_ = Some(ProgramReturn::Value(result)); } Value::PipeSubstitution(_) => {} @@ -774,8 +808,8 @@ mod tests { let parser = crate::parser::Parser::new(tokens); let program = parser.ast()?; let mut mem: ProgramMemory = Default::default(); - let mut engine = EngineConnection::new().await?; - let memory = execute(program, &mut mem, BodyType::Root, &mut engine)?; + let engine = EngineConnection::new().await?; + let memory = execute(program, &mut mem, BodyType::Root, &engine).await?; Ok(memory) } diff --git a/src/wasm-lib/kcl/src/std/extrude.rs b/src/wasm-lib/kcl/src/std/extrude.rs index 7b0af7225..d8162e426 100644 --- a/src/wasm-lib/kcl/src/std/extrude.rs +++ b/src/wasm-lib/kcl/src/std/extrude.rs @@ -11,10 +11,10 @@ use crate::{ }; /// Extrudes by a given amount. -pub fn extrude(args: &mut Args) -> Result { +pub async fn extrude(args: Args) -> Result { let (length, sketch_group) = args.get_number_sketch_group()?; - let result = inner_extrude(length, sketch_group, args)?; + let result = inner_extrude(length, sketch_group, args).await?; Ok(MemoryItem::ExtrudeGroup(result)) } @@ -23,7 +23,7 @@ pub fn extrude(args: &mut Args) -> Result { #[stdlib { name = "extrude" }] -fn inner_extrude(length: f64, sketch_group: Box, args: &mut Args) -> Result, KclError> { +async fn inner_extrude(length: f64, sketch_group: Box, args: Args) -> Result, KclError> { let id = uuid::Uuid::new_v4(); let cmd = kittycad::types::ModelingCmd::Extrude { @@ -31,7 +31,7 @@ fn inner_extrude(length: f64, sketch_group: Box, args: &mut Args) - distance: length, cap: true, }; - args.send_modeling_cmd(id, cmd)?; + args.send_modeling_cmd(id, cmd).await?; Ok(Box::new(ExtrudeGroup { id, @@ -46,7 +46,7 @@ fn inner_extrude(length: f64, sketch_group: Box, args: &mut Args) - } /// Returns the extrude wall transform. -pub fn get_extrude_wall_transform(args: &mut Args) -> Result { +pub async fn get_extrude_wall_transform(args: Args) -> Result { let (surface_name, extrude_group) = args.get_path_name_extrude_group()?; let result = inner_get_extrude_wall_transform(&surface_name, *extrude_group, args)?; Ok(MemoryItem::ExtrudeTransform(result)) @@ -59,8 +59,8 @@ pub fn get_extrude_wall_transform(args: &mut Args) -> Result Result { + args: Args, +) -> Result, KclError> { let surface = extrude_group.get_path_by_name(surface_name).ok_or_else(|| { KclError::Type(KclErrorDetails { message: format!( @@ -71,9 +71,9 @@ fn inner_get_extrude_wall_transform( }) })?; - Ok(ExtrudeTransform { + Ok(Box::new(ExtrudeTransform { position: surface.get_position(), rotation: surface.get_rotation(), meta: extrude_group.meta, - }) + })) } diff --git a/src/wasm-lib/kcl/src/std/math.rs b/src/wasm-lib/kcl/src/std/math.rs index 24e001da4..40530618b 100644 --- a/src/wasm-lib/kcl/src/std/math.rs +++ b/src/wasm-lib/kcl/src/std/math.rs @@ -11,7 +11,7 @@ use crate::{ }; /// Computes the cosine of a number (in radians). -pub fn cos(args: &mut Args) -> Result { +pub async fn cos(args: Args) -> Result { let num = args.get_number()?; let result = inner_cos(num)?; @@ -27,7 +27,7 @@ fn inner_cos(num: f64) -> Result { } /// Computes the sine of a number (in radians). -pub fn sin(args: &mut Args) -> Result { +pub async fn sin(args: Args) -> Result { let num = args.get_number()?; let result = inner_sin(num)?; @@ -43,7 +43,7 @@ fn inner_sin(num: f64) -> Result { } /// Computes the tangent of a number (in radians). -pub fn tan(args: &mut Args) -> Result { +pub async fn tan(args: Args) -> Result { let num = args.get_number()?; let result = inner_tan(num)?; @@ -59,7 +59,7 @@ fn inner_tan(num: f64) -> Result { } /// Return the value of `pi`. Archimedes’ constant (π). -pub fn pi(args: &mut Args) -> Result { +pub async fn pi(args: Args) -> Result { let result = inner_pi()?; args.make_user_val_from_f64(result) @@ -74,7 +74,7 @@ fn inner_pi() -> Result { } /// Computes the square root of a number. -pub fn sqrt(args: &mut Args) -> Result { +pub async fn sqrt(args: Args) -> Result { let num = args.get_number()?; let result = inner_sqrt(num)?; @@ -90,7 +90,7 @@ fn inner_sqrt(num: f64) -> Result { } /// Computes the absolute value of a number. -pub fn abs(args: &mut Args) -> Result { +pub async fn abs(args: Args) -> Result { let num = args.get_number()?; let result = inner_abs(num)?; @@ -106,7 +106,7 @@ fn inner_abs(num: f64) -> Result { } /// Computes the largest integer less than or equal to a number. -pub fn floor(args: &mut Args) -> Result { +pub async fn floor(args: Args) -> Result { let num = args.get_number()?; let result = inner_floor(num)?; @@ -122,7 +122,7 @@ fn inner_floor(num: f64) -> Result { } /// Computes the smallest integer greater than or equal to a number. -pub fn ceil(args: &mut Args) -> Result { +pub async fn ceil(args: Args) -> Result { let num = args.get_number()?; let result = inner_ceil(num)?; @@ -138,7 +138,7 @@ fn inner_ceil(num: f64) -> Result { } /// Computes the minimum of the given arguments. -pub fn min(args: &mut Args) -> Result { +pub async fn min(args: Args) -> Result { let nums = args.get_number_array()?; let result = inner_min(nums); @@ -161,7 +161,7 @@ fn inner_min(args: Vec) -> f64 { } /// Computes the maximum of the given arguments. -pub fn max(args: &mut Args) -> Result { +pub async fn max(args: Args) -> Result { let nums = args.get_number_array()?; let result = inner_max(nums); @@ -184,7 +184,7 @@ fn inner_max(args: Vec) -> f64 { } /// Computes the number to a power. -pub fn pow(args: &mut Args) -> Result { +pub async fn pow(args: Args) -> Result { let nums = args.get_number_array()?; if nums.len() > 2 { return Err(KclError::Type(KclErrorDetails { @@ -214,7 +214,7 @@ fn inner_pow(num: f64, pow: f64) -> Result { } /// Computes the arccosine of a number (in radians). -pub fn acos(args: &mut Args) -> Result { +pub async fn acos(args: Args) -> Result { let num = args.get_number()?; let result = inner_acos(num)?; @@ -230,7 +230,7 @@ fn inner_acos(num: f64) -> Result { } /// Computes the arcsine of a number (in radians). -pub fn asin(args: &mut Args) -> Result { +pub async fn asin(args: Args) -> Result { let num = args.get_number()?; let result = inner_asin(num)?; @@ -246,7 +246,7 @@ fn inner_asin(num: f64) -> Result { } /// Computes the arctangent of a number (in radians). -pub fn atan(args: &mut Args) -> Result { +pub async fn atan(args: Args) -> Result { let num = args.get_number()?; let result = inner_atan(num)?; @@ -266,7 +266,7 @@ fn inner_atan(num: f64) -> Result { /// The result might not be correctly rounded owing to implementation /// details; `log2()` can produce more accurate results for base 2, /// and `log10()` can produce more accurate results for base 10. -pub fn log(args: &mut Args) -> Result { +pub async fn log(args: Args) -> Result { let nums = args.get_number_array()?; if nums.len() > 2 { return Err(KclError::Type(KclErrorDetails { @@ -299,7 +299,7 @@ fn inner_log(num: f64, base: f64) -> Result { } /// Computes the base 2 logarithm of the number. -pub fn log2(args: &mut Args) -> Result { +pub async fn log2(args: Args) -> Result { let num = args.get_number()?; let result = inner_log2(num)?; @@ -315,7 +315,7 @@ fn inner_log2(num: f64) -> Result { } /// Computes the base 10 logarithm of the number. -pub fn log10(args: &mut Args) -> Result { +pub async fn log10(args: Args) -> Result { let num = args.get_number()?; let result = inner_log10(num)?; @@ -331,7 +331,7 @@ fn inner_log10(num: f64) -> Result { } /// Computes the natural logarithm of the number. -pub fn ln(args: &mut Args) -> Result { +pub async fn ln(args: Args) -> Result { let num = args.get_number()?; let result = inner_ln(num)?; @@ -347,7 +347,7 @@ fn inner_ln(num: f64) -> Result { } /// Return the value of Euler’s number `e`. -pub fn e(args: &mut Args) -> Result { +pub async fn e(args: Args) -> Result { let result = inner_e()?; args.make_user_val_from_f64(result) @@ -362,7 +362,7 @@ fn inner_e() -> Result { } /// Return the value of `tau`. The full circle constant (τ). Equal to 2π. -pub fn tau(args: &mut Args) -> Result { +pub async fn tau(args: Args) -> Result { let result = inner_tau()?; args.make_user_val_from_f64(result) diff --git a/src/wasm-lib/kcl/src/std/mod.rs b/src/wasm-lib/kcl/src/std/mod.rs index 13d913ae2..fc923efa3 100644 --- a/src/wasm-lib/kcl/src/std/mod.rs +++ b/src/wasm-lib/kcl/src/std/mod.rs @@ -10,6 +10,7 @@ use std::collections::HashMap; use anyhow::Result; use derive_docs::stdlib; +use kittycad::types::OkWebSocketResponseData; use parse_display::{Display, FromStr}; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; @@ -21,7 +22,7 @@ use crate::{ executor::{ExtrudeGroup, MemoryItem, Metadata, SketchGroup, SourceRange}, }; -pub type StdFn = fn(&mut Args) -> Result; +pub type StdFn = fn(Args) -> std::pin::Pin>>>; pub type FnMap = HashMap; pub struct StdLib { @@ -102,15 +103,15 @@ impl Default for StdLib { } } -#[derive(Debug)] -pub struct Args<'a> { +#[derive(Debug, Clone)] +pub struct Args { pub args: Vec, pub source_range: SourceRange, - engine: &'a mut EngineConnection, + engine: EngineConnection, } -impl<'a> Args<'a> { - pub fn new(args: Vec, source_range: SourceRange, engine: &'a mut EngineConnection) -> Self { +impl Args { + pub fn new(args: Vec, source_range: SourceRange, engine: EngineConnection) -> Self { Self { args, source_range, @@ -118,8 +119,12 @@ impl<'a> Args<'a> { } } - pub fn send_modeling_cmd(&mut self, id: uuid::Uuid, cmd: kittycad::types::ModelingCmd) -> Result<(), KclError> { - self.engine.send_modeling_cmd(id, self.source_range, cmd) + pub async fn send_modeling_cmd( + &self, + id: uuid::Uuid, + cmd: kittycad::types::ModelingCmd, + ) -> Result { + self.engine.send_modeling_cmd(id, self.source_range, cmd).await } fn make_user_val_from_json(&self, j: serde_json::Value) -> Result { @@ -443,7 +448,7 @@ impl<'a> Args<'a> { /// Render a model. // This never actually gets called so this is fine. -pub fn show(args: &mut Args) -> Result { +pub async fn show<'a>(args: Args) -> Result { let sketch_group = args.get_sketch_group()?; inner_show(sketch_group); @@ -457,7 +462,7 @@ pub fn show(args: &mut Args) -> Result { fn inner_show(_sketch: Box) {} /// Returns the length of the given leg. -pub fn leg_length(args: &mut Args) -> Result { +pub async fn leg_length(args: Args) -> Result { let (hypotenuse, leg) = args.get_hypotenuse_leg()?; let result = inner_leg_length(hypotenuse, leg); args.make_user_val_from_f64(result) @@ -472,7 +477,7 @@ fn inner_leg_length(hypotenuse: f64, leg: f64) -> f64 { } /// Returns the angle of the given leg for x. -pub fn leg_angle_x(args: &mut Args) -> Result { +pub async fn leg_angle_x(args: Args) -> Result { let (hypotenuse, leg) = args.get_hypotenuse_leg()?; let result = inner_leg_angle_x(hypotenuse, leg); args.make_user_val_from_f64(result) @@ -487,7 +492,7 @@ fn inner_leg_angle_x(hypotenuse: f64, leg: f64) -> f64 { } /// Returns the angle of the given leg for y. -pub fn leg_angle_y(args: &mut Args) -> Result { +pub async fn leg_angle_y(args: Args) -> Result { let (hypotenuse, leg) = args.get_hypotenuse_leg()?; let result = inner_leg_angle_y(hypotenuse, leg); args.make_user_val_from_f64(result) diff --git a/src/wasm-lib/kcl/src/std/segment.rs b/src/wasm-lib/kcl/src/std/segment.rs index 47e467d9b..c849e4825 100644 --- a/src/wasm-lib/kcl/src/std/segment.rs +++ b/src/wasm-lib/kcl/src/std/segment.rs @@ -11,9 +11,9 @@ use crate::{ }; /// Returns the segment end of x. -pub fn segment_end_x(args: &mut Args) -> Result { +pub async fn segment_end_x(args: Args) -> Result { let (segment_name, sketch_group) = args.get_segment_name_sketch_group()?; - let result = inner_segment_end_x(&segment_name, sketch_group, args)?; + let result = inner_segment_end_x(&segment_name, sketch_group, args.clone())?; args.make_user_val_from_f64(result) } @@ -22,7 +22,7 @@ pub fn segment_end_x(args: &mut Args) -> Result { #[stdlib { name = "segEndX", }] -fn inner_segment_end_x(segment_name: &str, sketch_group: Box, args: &mut Args) -> Result { +fn inner_segment_end_x(segment_name: &str, sketch_group: Box, args: Args) -> Result { let line = sketch_group.get_base_by_name_or_start(segment_name).ok_or_else(|| { KclError::Type(KclErrorDetails { message: format!( @@ -37,9 +37,9 @@ fn inner_segment_end_x(segment_name: &str, sketch_group: Box, args: } /// Returns the segment end of y. -pub fn segment_end_y(args: &mut Args) -> Result { +pub async fn segment_end_y(args: Args) -> Result { let (segment_name, sketch_group) = args.get_segment_name_sketch_group()?; - let result = inner_segment_end_y(&segment_name, sketch_group, args)?; + let result = inner_segment_end_y(&segment_name, sketch_group, args.clone())?; args.make_user_val_from_f64(result) } @@ -48,7 +48,7 @@ pub fn segment_end_y(args: &mut Args) -> Result { #[stdlib { name = "segEndY", }] -fn inner_segment_end_y(segment_name: &str, sketch_group: Box, args: &mut Args) -> Result { +fn inner_segment_end_y(segment_name: &str, sketch_group: Box, args: Args) -> Result { let line = sketch_group.get_base_by_name_or_start(segment_name).ok_or_else(|| { KclError::Type(KclErrorDetails { message: format!( @@ -63,9 +63,9 @@ fn inner_segment_end_y(segment_name: &str, sketch_group: Box, args: } /// Returns the last segment of x. -pub fn last_segment_x(args: &mut Args) -> Result { +pub async fn last_segment_x(args: Args) -> Result { let sketch_group = args.get_sketch_group()?; - let result = inner_last_segment_x(sketch_group, args)?; + let result = inner_last_segment_x(sketch_group, args.clone())?; args.make_user_val_from_f64(result) } @@ -74,7 +74,7 @@ pub fn last_segment_x(args: &mut Args) -> Result { #[stdlib { name = "lastSegX", }] -fn inner_last_segment_x(sketch_group: Box, args: &mut Args) -> Result { +fn inner_last_segment_x(sketch_group: Box, args: Args) -> Result { let last_line = sketch_group .value .last() @@ -93,9 +93,9 @@ fn inner_last_segment_x(sketch_group: Box, args: &mut Args) -> Resu } /// Returns the last segment of y. -pub fn last_segment_y(args: &mut Args) -> Result { +pub async fn last_segment_y(args: Args) -> Result { let sketch_group = args.get_sketch_group()?; - let result = inner_last_segment_y(sketch_group, args)?; + let result = inner_last_segment_y(sketch_group, args.clone())?; args.make_user_val_from_f64(result) } @@ -104,7 +104,7 @@ pub fn last_segment_y(args: &mut Args) -> Result { #[stdlib { name = "lastSegY", }] -fn inner_last_segment_y(sketch_group: Box, args: &mut Args) -> Result { +fn inner_last_segment_y(sketch_group: Box, args: Args) -> Result { let last_line = sketch_group .value .last() @@ -123,9 +123,9 @@ fn inner_last_segment_y(sketch_group: Box, args: &mut Args) -> Resu } /// Returns the length of the segment. -pub fn segment_length(args: &mut Args) -> Result { +pub async fn segment_length(args: Args) -> Result { let (segment_name, sketch_group) = args.get_segment_name_sketch_group()?; - let result = inner_segment_length(&segment_name, sketch_group, args)?; + let result = inner_segment_length(&segment_name, sketch_group, args.clone())?; args.make_user_val_from_f64(result) } @@ -133,7 +133,7 @@ pub fn segment_length(args: &mut Args) -> Result { #[stdlib { name = "segLen", }] -fn inner_segment_length(segment_name: &str, sketch_group: Box, args: &mut Args) -> Result { +fn inner_segment_length(segment_name: &str, sketch_group: Box, args: Args) -> Result { let path = sketch_group.get_path_by_name(segment_name).ok_or_else(|| { KclError::Type(KclErrorDetails { message: format!( @@ -151,10 +151,10 @@ fn inner_segment_length(segment_name: &str, sketch_group: Box, args } /// Returns the angle of the segment. -pub fn segment_angle(args: &mut Args) -> Result { +pub async fn segment_angle(args: Args) -> Result { let (segment_name, sketch_group) = args.get_segment_name_sketch_group()?; - let result = inner_segment_angle(&segment_name, sketch_group, args)?; + let result = inner_segment_angle(&segment_name, sketch_group, args.clone())?; args.make_user_val_from_f64(result) } @@ -162,7 +162,7 @@ pub fn segment_angle(args: &mut Args) -> Result { #[stdlib { name = "segAng", }] -fn inner_segment_angle(segment_name: &str, sketch_group: Box, args: &mut Args) -> Result { +fn inner_segment_angle(segment_name: &str, sketch_group: Box, args: Args) -> Result { let path = sketch_group.get_path_by_name(segment_name).ok_or_else(|| { KclError::Type(KclErrorDetails { message: format!( @@ -180,9 +180,9 @@ fn inner_segment_angle(segment_name: &str, sketch_group: Box, args: } /// Returns the angle to match the given length for x. -pub fn angle_to_match_length_x(args: &mut Args) -> Result { +pub async fn angle_to_match_length_x(args: Args) -> Result { let (segment_name, to, sketch_group) = args.get_segment_name_to_number_sketch_group()?; - let result = inner_angle_to_match_length_x(&segment_name, to, sketch_group, args)?; + let result = inner_angle_to_match_length_x(&segment_name, to, sketch_group, args.clone())?; args.make_user_val_from_f64(result) } @@ -194,7 +194,7 @@ fn inner_angle_to_match_length_x( segment_name: &str, to: f64, sketch_group: Box, - args: &mut Args, + args: Args, ) -> Result { let path = sketch_group.get_path_by_name(segment_name).ok_or_else(|| { KclError::Type(KclErrorDetails { @@ -235,9 +235,9 @@ fn inner_angle_to_match_length_x( } /// Returns the angle to match the given length for y. -pub fn angle_to_match_length_y(args: &mut Args) -> Result { +pub async fn angle_to_match_length_y(args: Args) -> Result { let (segment_name, to, sketch_group) = args.get_segment_name_to_number_sketch_group()?; - let result = inner_angle_to_match_length_y(&segment_name, to, sketch_group, args)?; + let result = inner_angle_to_match_length_y(&segment_name, to, sketch_group, args.clone())?; args.make_user_val_from_f64(result) } @@ -249,7 +249,7 @@ fn inner_angle_to_match_length_y( segment_name: &str, to: f64, sketch_group: Box, - args: &mut Args, + args: Args, ) -> Result { let path = sketch_group.get_path_by_name(segment_name).ok_or_else(|| { KclError::Type(KclErrorDetails { diff --git a/src/wasm-lib/kcl/src/std/sketch.rs b/src/wasm-lib/kcl/src/std/sketch.rs index 86b0374e5..f5d086f9e 100644 --- a/src/wasm-lib/kcl/src/std/sketch.rs +++ b/src/wasm-lib/kcl/src/std/sketch.rs @@ -33,10 +33,10 @@ pub enum LineToData { } /// Draw a line to a point. -pub fn line_to(args: &mut Args) -> Result { +pub async fn line_to(args: Args) -> Result { let (data, sketch_group): (LineToData, Box) = args.get_data_and_sketch_group()?; - let new_sketch_group = inner_line_to(data, sketch_group, args)?; + let new_sketch_group = inner_line_to(data, sketch_group, args).await?; Ok(MemoryItem::SketchGroup(new_sketch_group)) } @@ -44,10 +44,10 @@ pub fn line_to(args: &mut Args) -> Result { #[stdlib { name = "lineTo", }] -fn inner_line_to( +async fn inner_line_to( data: LineToData, sketch_group: Box, - args: &mut Args, + args: Args, ) -> Result, KclError> { let from = sketch_group.get_coords_from_paths()?; let to = match data { @@ -70,7 +70,8 @@ fn inner_line_to( relative: false, }, }, - )?; + ) + .await?; let current_path = Path::ToPoint { base: BasePath { @@ -111,10 +112,10 @@ pub enum AxisLineToData { } /// Draw a line to a point on the x-axis. -pub fn x_line_to(args: &mut Args) -> Result { +pub async fn x_line_to(args: Args) -> Result { let (data, sketch_group): (AxisLineToData, Box) = args.get_data_and_sketch_group()?; - let new_sketch_group = inner_x_line_to(data, sketch_group, args)?; + let new_sketch_group = inner_x_line_to(data, sketch_group, args).await?; Ok(MemoryItem::SketchGroup(new_sketch_group)) } @@ -122,10 +123,10 @@ pub fn x_line_to(args: &mut Args) -> Result { #[stdlib { name = "xLineTo", }] -fn inner_x_line_to( +async fn inner_x_line_to( data: AxisLineToData, sketch_group: Box, - args: &mut Args, + args: Args, ) -> Result, KclError> { let from = sketch_group.get_coords_from_paths()?; @@ -134,16 +135,16 @@ fn inner_x_line_to( AxisLineToData::Point(data) => LineToData::Point([data, from.y]), }; - let new_sketch_group = inner_line_to(line_to_data, sketch_group, args)?; + let new_sketch_group = inner_line_to(line_to_data, sketch_group, args).await?; Ok(new_sketch_group) } /// Draw a line to a point on the y-axis. -pub fn y_line_to(args: &mut Args) -> Result { +pub async fn y_line_to(args: Args) -> Result { let (data, sketch_group): (AxisLineToData, Box) = args.get_data_and_sketch_group()?; - let new_sketch_group = inner_y_line_to(data, sketch_group, args)?; + let new_sketch_group = inner_y_line_to(data, sketch_group, args).await?; Ok(MemoryItem::SketchGroup(new_sketch_group)) } @@ -151,10 +152,10 @@ pub fn y_line_to(args: &mut Args) -> Result { #[stdlib { name = "yLineTo", }] -fn inner_y_line_to( +async fn inner_y_line_to( data: AxisLineToData, sketch_group: Box, - args: &mut Args, + args: Args, ) -> Result, KclError> { let from = sketch_group.get_coords_from_paths()?; @@ -163,7 +164,7 @@ fn inner_y_line_to( AxisLineToData::Point(data) => LineToData::Point([from.x, data]), }; - let new_sketch_group = inner_line_to(line_to_data, sketch_group, args)?; + let new_sketch_group = inner_line_to(line_to_data, sketch_group, args).await?; Ok(new_sketch_group) } @@ -184,10 +185,10 @@ pub enum LineData { } /// Draw a line. -pub fn line(args: &mut Args) -> Result { +pub async fn line(args: Args) -> Result { let (data, sketch_group): (LineData, Box) = args.get_data_and_sketch_group()?; - let new_sketch_group = inner_line(data, sketch_group, args)?; + let new_sketch_group = inner_line(data, sketch_group, args).await?; Ok(MemoryItem::SketchGroup(new_sketch_group)) } @@ -195,7 +196,7 @@ pub fn line(args: &mut Args) -> Result { #[stdlib { name = "line", }] -fn inner_line(data: LineData, sketch_group: Box, args: &mut Args) -> Result, KclError> { +async fn inner_line(data: LineData, sketch_group: Box, args: Args) -> Result, KclError> { let from = sketch_group.get_coords_from_paths()?; let inner_args = match &data { LineData::PointWithTag { to, .. } => *to, @@ -220,7 +221,8 @@ fn inner_line(data: LineData, sketch_group: Box, args: &mut Args) - relative: true, }, }, - )?; + ) + .await?; let current_path = Path::ToPoint { base: BasePath { @@ -261,10 +263,10 @@ pub enum AxisLineData { } /// Draw a line on the x-axis. -pub fn x_line(args: &mut Args) -> Result { +pub async fn x_line(args: Args) -> Result { let (data, sketch_group): (AxisLineData, Box) = args.get_data_and_sketch_group()?; - let new_sketch_group = inner_x_line(data, sketch_group, args)?; + let new_sketch_group = inner_x_line(data, sketch_group, args).await?; Ok(MemoryItem::SketchGroup(new_sketch_group)) } @@ -272,25 +274,25 @@ pub fn x_line(args: &mut Args) -> Result { #[stdlib { name = "xLine", }] -fn inner_x_line( +async fn inner_x_line( data: AxisLineData, sketch_group: Box, - args: &mut Args, + args: Args, ) -> Result, KclError> { let line_data = match data { AxisLineData::LengthWithTag { length, tag } => LineData::PointWithTag { to: [length, 0.0], tag }, AxisLineData::Length(length) => LineData::Point([length, 0.0]), }; - let new_sketch_group = inner_line(line_data, sketch_group, args)?; + let new_sketch_group = inner_line(line_data, sketch_group, args).await?; Ok(new_sketch_group) } /// Draw a line on the y-axis. -pub fn y_line(args: &mut Args) -> Result { +pub async fn y_line(args: Args) -> Result { let (data, sketch_group): (AxisLineData, Box) = args.get_data_and_sketch_group()?; - let new_sketch_group = inner_y_line(data, sketch_group, args)?; + let new_sketch_group = inner_y_line(data, sketch_group, args).await?; Ok(MemoryItem::SketchGroup(new_sketch_group)) } @@ -298,17 +300,17 @@ pub fn y_line(args: &mut Args) -> Result { #[stdlib { name = "yLine", }] -fn inner_y_line( +async fn inner_y_line( data: AxisLineData, sketch_group: Box, - args: &mut Args, + args: Args, ) -> Result, KclError> { let line_data = match data { AxisLineData::LengthWithTag { length, tag } => LineData::PointWithTag { to: [0.0, length], tag }, AxisLineData::Length(length) => LineData::Point([0.0, length]), }; - let new_sketch_group = inner_line(line_data, sketch_group, args)?; + let new_sketch_group = inner_line(line_data, sketch_group, args).await?; Ok(new_sketch_group) } @@ -331,10 +333,10 @@ pub enum AngledLineData { } /// Draw an angled line. -pub fn angled_line(args: &mut Args) -> Result { +pub async fn angled_line(args: Args) -> Result { let (data, sketch_group): (AngledLineData, Box) = args.get_data_and_sketch_group()?; - let new_sketch_group = inner_angled_line(data, sketch_group, args)?; + let new_sketch_group = inner_angled_line(data, sketch_group, args).await?; Ok(MemoryItem::SketchGroup(new_sketch_group)) } @@ -342,10 +344,10 @@ pub fn angled_line(args: &mut Args) -> Result { #[stdlib { name = "angledLine", }] -fn inner_angled_line( +async fn inner_angled_line( data: AngledLineData, sketch_group: Box, - args: &mut Args, + args: Args, ) -> Result, KclError> { let from = sketch_group.get_coords_from_paths()?; let (angle, length) = match &data { @@ -393,7 +395,8 @@ fn inner_angled_line( relative, }, }, - )?; + ) + .await?; let mut new_sketch_group = sketch_group.clone(); new_sketch_group.value.push(current_path); @@ -401,10 +404,10 @@ fn inner_angled_line( } /// Draw an angled line of a given x length. -pub fn angled_line_of_x_length(args: &mut Args) -> Result { +pub async fn angled_line_of_x_length(args: Args) -> Result { let (data, sketch_group): (AngledLineData, Box) = args.get_data_and_sketch_group()?; - let new_sketch_group = inner_angled_line_of_x_length(data, sketch_group, args)?; + let new_sketch_group = inner_angled_line_of_x_length(data, sketch_group, args).await?; Ok(MemoryItem::SketchGroup(new_sketch_group)) } @@ -412,10 +415,10 @@ pub fn angled_line_of_x_length(args: &mut Args) -> Result #[stdlib { name = "angledLineOfXLength", }] -fn inner_angled_line_of_x_length( +async fn inner_angled_line_of_x_length( data: AngledLineData, sketch_group: Box, - args: &mut Args, + args: Args, ) -> Result, KclError> { let (angle, length) = match &data { AngledLineData::AngleWithTag { angle, length, .. } => (*angle, *length), @@ -432,7 +435,8 @@ fn inner_angled_line_of_x_length( }, sketch_group, args, - )?; + ) + .await?; Ok(new_sketch_group) } @@ -456,10 +460,10 @@ pub enum AngledLineToData { } /// Draw an angled line to a given x coordinate. -pub fn angled_line_to_x(args: &mut Args) -> Result { +pub async fn angled_line_to_x(args: Args) -> Result { let (data, sketch_group): (AngledLineToData, Box) = args.get_data_and_sketch_group()?; - let new_sketch_group = inner_angled_line_to_x(data, sketch_group, args)?; + let new_sketch_group = inner_angled_line_to_x(data, sketch_group, args).await?; Ok(MemoryItem::SketchGroup(new_sketch_group)) } @@ -467,10 +471,10 @@ pub fn angled_line_to_x(args: &mut Args) -> Result { #[stdlib { name = "angledLineToX", }] -fn inner_angled_line_to_x( +async fn inner_angled_line_to_x( data: AngledLineToData, sketch_group: Box, - args: &mut Args, + args: Args, ) -> Result, KclError> { let from = sketch_group.get_coords_from_paths()?; let (angle, x_to) = match &data { @@ -490,15 +494,16 @@ fn inner_angled_line_to_x( }, sketch_group, args, - )?; + ) + .await?; Ok(new_sketch_group) } /// Draw an angled line of a given y length. -pub fn angled_line_of_y_length(args: &mut Args) -> Result { +pub async fn angled_line_of_y_length(args: Args) -> Result { let (data, sketch_group): (AngledLineData, Box) = args.get_data_and_sketch_group()?; - let new_sketch_group = inner_angled_line_of_y_length(data, sketch_group, args)?; + let new_sketch_group = inner_angled_line_of_y_length(data, sketch_group, args).await?; Ok(MemoryItem::SketchGroup(new_sketch_group)) } @@ -507,10 +512,10 @@ pub fn angled_line_of_y_length(args: &mut Args) -> Result #[stdlib { name = "angledLineOfYLength", }] -fn inner_angled_line_of_y_length( +async fn inner_angled_line_of_y_length( data: AngledLineData, sketch_group: Box, - args: &mut Args, + args: Args, ) -> Result, KclError> { let (angle, length) = match &data { AngledLineData::AngleWithTag { angle, length, .. } => (*angle, *length), @@ -527,16 +532,17 @@ fn inner_angled_line_of_y_length( }, sketch_group, args, - )?; + ) + .await?; Ok(new_sketch_group) } /// Draw an angled line to a given y coordinate. -pub fn angled_line_to_y(args: &mut Args) -> Result { +pub async fn angled_line_to_y(args: Args) -> Result { let (data, sketch_group): (AngledLineToData, Box) = args.get_data_and_sketch_group()?; - let new_sketch_group = inner_angled_line_to_y(data, sketch_group, args)?; + let new_sketch_group = inner_angled_line_to_y(data, sketch_group, args).await?; Ok(MemoryItem::SketchGroup(new_sketch_group)) } @@ -544,10 +550,10 @@ pub fn angled_line_to_y(args: &mut Args) -> Result { #[stdlib { name = "angledLineToY", }] -fn inner_angled_line_to_y( +async fn inner_angled_line_to_y( data: AngledLineToData, sketch_group: Box, - args: &mut Args, + args: Args, ) -> Result, KclError> { let from = sketch_group.get_coords_from_paths()?; let (angle, y_to) = match &data { @@ -567,7 +573,8 @@ fn inner_angled_line_to_y( }, sketch_group, args, - )?; + ) + .await?; Ok(new_sketch_group) } @@ -588,9 +595,9 @@ pub struct AngeledLineThatIntersectsData { } /// Draw an angled line that intersects with a given line. -pub fn angled_line_that_intersects(args: &mut Args) -> Result { +pub async fn angled_line_that_intersects(args: Args) -> Result { let (data, sketch_group): (AngeledLineThatIntersectsData, Box) = args.get_data_and_sketch_group()?; - let new_sketch_group = inner_angled_line_that_intersects(data, sketch_group, args)?; + let new_sketch_group = inner_angled_line_that_intersects(data, sketch_group, args).await?; Ok(MemoryItem::SketchGroup(new_sketch_group)) } @@ -598,10 +605,10 @@ pub fn angled_line_that_intersects(args: &mut Args) -> Result, - args: &mut Args, + args: Args, ) -> Result, KclError> { let intersect_path = sketch_group .get_path_by_name(&data.intersect_tag) @@ -630,15 +637,15 @@ fn inner_angled_line_that_intersects( LineToData::Point(to.into()) }; - let new_sketch_group = inner_line_to(line_to_data, sketch_group, args)?; + let new_sketch_group = inner_line_to(line_to_data, sketch_group, args).await?; Ok(new_sketch_group) } /// Start a sketch at a given point. -pub fn start_sketch_at(args: &mut Args) -> Result { +pub async fn start_sketch_at(args: Args) -> Result { let data: LineData = args.get_data()?; - let sketch_group = inner_start_sketch_at(data, args)?; + let sketch_group = inner_start_sketch_at(data, args).await?; Ok(MemoryItem::SketchGroup(sketch_group)) } @@ -646,7 +653,7 @@ pub fn start_sketch_at(args: &mut Args) -> Result { #[stdlib { name = "startSketchAt", }] -fn inner_start_sketch_at(data: LineData, args: &mut Args) -> Result, KclError> { +async fn inner_start_sketch_at(data: LineData, args: Args) -> Result, KclError> { let to = match &data { LineData::PointWithTag { to, .. } => *to, LineData::Point(to) => *to, @@ -655,7 +662,7 @@ fn inner_start_sketch_at(data: LineData, args: &mut Args) -> Result Result Result Result { +pub async fn close(args: Args) -> Result { let sketch_group = args.get_sketch_group()?; - let new_sketch_group = inner_close(sketch_group, args)?; + let new_sketch_group = inner_close(sketch_group, args).await?; Ok(MemoryItem::SketchGroup(new_sketch_group)) } @@ -706,7 +714,7 @@ pub fn close(args: &mut Args) -> Result { #[stdlib { name = "close", }] -fn inner_close(sketch_group: Box, args: &mut Args) -> Result, KclError> { +async fn inner_close(sketch_group: Box, args: Args) -> Result, KclError> { let from = sketch_group.get_coords_from_paths()?; let to: Point2d = sketch_group.start.from.into(); @@ -717,7 +725,8 @@ fn inner_close(sketch_group: Box, args: &mut Args) -> Result Result { +pub async fn arc(args: Args) -> Result { let (data, sketch_group): (ArcData, Box) = args.get_data_and_sketch_group()?; - let new_sketch_group = inner_arc(data, sketch_group, args)?; + let new_sketch_group = inner_arc(data, sketch_group, args).await?; Ok(MemoryItem::SketchGroup(new_sketch_group)) } @@ -795,7 +804,7 @@ pub fn arc(args: &mut Args) -> Result { #[stdlib { name = "arc", }] -fn inner_arc(data: ArcData, sketch_group: Box, args: &mut Args) -> Result, KclError> { +async fn inner_arc(data: ArcData, sketch_group: Box, args: Args) -> Result, KclError> { let from: Point2d = sketch_group.get_coords_from_paths()?; let (center, angle_start, angle_end, radius, end) = match &data { @@ -844,7 +853,8 @@ fn inner_arc(data: ArcData, sketch_group: Box, args: &mut Args) -> relative: false, }, }, - )?; + ) + .await?; // TODO: Dont do this (move path pen) - mike // lets review what the needs are here and see if any existing arc endpoints can accomplish this @@ -863,7 +873,8 @@ fn inner_arc(data: ArcData, sketch_group: Box, args: &mut Args) -> z: 0.0, }, }, - )?; + ) + .await?; let current_path = Path::ToPoint { base: BasePath { @@ -916,10 +927,10 @@ pub enum BezierData { } /// Draw a bezier curve. -pub fn bezier_curve(args: &mut Args) -> Result { +pub async fn bezier_curve(args: Args) -> Result { let (data, sketch_group): (BezierData, Box) = args.get_data_and_sketch_group()?; - let new_sketch_group = inner_bezier_curve(data, sketch_group, args)?; + let new_sketch_group = inner_bezier_curve(data, sketch_group, args).await?; Ok(MemoryItem::SketchGroup(new_sketch_group)) } @@ -927,10 +938,10 @@ pub fn bezier_curve(args: &mut Args) -> Result { #[stdlib { name = "bezierCurve", }] -fn inner_bezier_curve( +async fn inner_bezier_curve( data: BezierData, sketch_group: Box, - args: &mut Args, + args: Args, ) -> Result, KclError> { let from = sketch_group.get_coords_from_paths()?; @@ -970,7 +981,8 @@ fn inner_bezier_curve( relative, }, }, - )?; + ) + .await?; let current_path = Path::ToPoint { base: BasePath { diff --git a/src/wasm-lib/src/lib.rs b/src/wasm-lib/src/lib.rs index 8e1047e1f..b6044f0d4 100644 --- a/src/wasm-lib/src/lib.rs +++ b/src/wasm-lib/src/lib.rs @@ -21,11 +21,12 @@ pub async fn execute_wasm( let program: kcl_lib::ast::types::Program = serde_json::from_str(program_str).map_err(|e| e.to_string())?; let mut mem: kcl_lib::executor::ProgramMemory = serde_json::from_str(memory_str).map_err(|e| e.to_string())?; - let mut engine = kcl_lib::engine::EngineConnection::new(manager) + let engine = kcl_lib::engine::EngineConnection::new(manager) .await .map_err(|e| format!("{:?}", e))?; - let memory = kcl_lib::executor::execute(program, &mut mem, kcl_lib::executor::BodyType::Root, &mut engine) + let memory = kcl_lib::executor::execute(program, &mut mem, kcl_lib::executor::BodyType::Root, &engine) + .await .map_err(String::from)?; // The serde-wasm-bindgen does not work here because of weird HashMap issues so we use the // gloo-serialize crate instead. diff --git a/src/wasm-lib/tests/executor/main.rs b/src/wasm-lib/tests/executor/main.rs index f34ed2c8d..8777740d3 100644 --- a/src/wasm-lib/tests/executor/main.rs +++ b/src/wasm-lib/tests/executor/main.rs @@ -35,12 +35,12 @@ async fn execute_and_snapshot(code: &str) -> Result { let parser = kcl_lib::parser::Parser::new(tokens); let program = parser.ast()?; let mut mem: kcl_lib::executor::ProgramMemory = Default::default(); - let mut engine = kcl_lib::engine::EngineConnection::new(ws).await?; - let _ = kcl_lib::executor::execute(program, &mut mem, kcl_lib::executor::BodyType::Root, &mut engine)?; + let engine = kcl_lib::engine::EngineConnection::new(ws).await?; + let _ = kcl_lib::executor::execute(program, &mut mem, kcl_lib::executor::BodyType::Root, &engine).await?; // Send a snapshot request to the engine. let resp = engine - .send_modeling_cmd_get_response( + .send_modeling_cmd( uuid::Uuid::new_v4(), kcl_lib::executor::SourceRange::default(), kittycad::types::ModelingCmd::TakeSnapshot { diff --git a/src/wasm-lib/tests/executor/outputs/member_expression_sketch_group.png b/src/wasm-lib/tests/executor/outputs/member_expression_sketch_group.png index 364ead9ef..21fdef139 100644 Binary files a/src/wasm-lib/tests/executor/outputs/member_expression_sketch_group.png and b/src/wasm-lib/tests/executor/outputs/member_expression_sketch_group.png differ diff --git a/src/wasm-lib/tests/modify/main.rs b/src/wasm-lib/tests/modify/main.rs index f570b1102..9dea6e5d7 100644 --- a/src/wasm-lib/tests/modify/main.rs +++ b/src/wasm-lib/tests/modify/main.rs @@ -37,13 +37,9 @@ async fn setup(code: &str, name: &str) -> Result<(EngineConnection, Program, uui let parser = kcl_lib::parser::Parser::new(tokens); let program = parser.ast()?; let mut mem: kcl_lib::executor::ProgramMemory = Default::default(); - let mut engine = kcl_lib::engine::EngineConnection::new(ws).await?; - let memory = kcl_lib::executor::execute( - program.clone(), - &mut mem, - kcl_lib::executor::BodyType::Root, - &mut engine, - )?; + let engine = kcl_lib::engine::EngineConnection::new(ws).await?; + let memory = + kcl_lib::executor::execute(program.clone(), &mut mem, kcl_lib::executor::BodyType::Root, &engine).await?; // We need to get the sketch ID. // Get the sketch group ID from memory. @@ -53,38 +49,44 @@ async fn setup(code: &str, name: &str) -> Result<(EngineConnection, Program, uui let sketch_id = sketch_group.id; let plane_id = uuid::Uuid::new_v4(); - engine.send_modeling_cmd( - plane_id, - SourceRange::default(), - ModelingCmd::MakePlane { - clobber: false, - origin: Point3D { x: 0.0, y: 0.0, z: 0.0 }, - size: 60.0, - x_axis: Point3D { x: 1.0, y: 0.0, z: 0.0 }, - y_axis: Point3D { x: 0.0, y: 1.0, z: 0.0 }, - }, - )?; + engine + .send_modeling_cmd( + plane_id, + SourceRange::default(), + ModelingCmd::MakePlane { + clobber: false, + origin: Point3D { x: 0.0, y: 0.0, z: 0.0 }, + size: 60.0, + x_axis: Point3D { x: 1.0, y: 0.0, z: 0.0 }, + y_axis: Point3D { x: 0.0, y: 1.0, z: 0.0 }, + }, + ) + .await?; // Enter sketch mode. // We can't get control points without being in sketch mode. // You can however get path info without sketch mode. - engine.send_modeling_cmd( - uuid::Uuid::new_v4(), - SourceRange::default(), - ModelingCmd::SketchModeEnable { - animated: false, - ortho: true, - plane_id, - }, - )?; + engine + .send_modeling_cmd( + uuid::Uuid::new_v4(), + SourceRange::default(), + ModelingCmd::SketchModeEnable { + animated: false, + ortho: true, + plane_id, + }, + ) + .await?; // Enter edit mode. // We can't get control points of an existing sketch without being in edit mode. - engine.send_modeling_cmd( - uuid::Uuid::new_v4(), - SourceRange::default(), - ModelingCmd::EditModeEnter { target: sketch_id }, - )?; + engine + .send_modeling_cmd( + uuid::Uuid::new_v4(), + SourceRange::default(), + ModelingCmd::EditModeEnter { target: sketch_id }, + ) + .await?; Ok((engine, program, sketch_id)) }