From 1554b5059a865324ccb481b0df71d5a4a131f069 Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Tue, 28 Jan 2025 12:03:26 +1300 Subject: [PATCH] Move caching logic to inside execution Signed-off-by: Nick Cameron --- src/wasm-lib/derive-docs/src/lib.rs | 2 +- .../derive-docs/tests/args_with_lifetime.gen | 2 +- .../derive-docs/tests/args_with_refs.gen | 2 +- src/wasm-lib/derive-docs/tests/array.gen | 4 +- src/wasm-lib/derive-docs/tests/box.gen | 2 +- .../tests/doc_comment_with_code.gen | 4 +- src/wasm-lib/derive-docs/tests/lineTo.gen | 4 +- src/wasm-lib/derive-docs/tests/min.gen | 4 +- src/wasm-lib/derive-docs/tests/option.gen | 2 +- .../derive-docs/tests/option_input_format.gen | 2 +- .../tests/return_vec_box_sketch.gen | 2 +- .../derive-docs/tests/return_vec_sketch.gen | 2 +- src/wasm-lib/derive-docs/tests/show.gen | 2 +- .../tests/test_args_with_exec_state.gen | 2 +- src/wasm-lib/kcl-test-server/src/lib.rs | 7 +- src/wasm-lib/kcl-to-core/src/lib.rs | 2 +- src/wasm-lib/kcl/src/execution/cache.rs | 230 +++++++----------- src/wasm-lib/kcl/src/execution/mod.rs | 216 +++++++++------- src/wasm-lib/kcl/src/lib.rs | 5 +- src/wasm-lib/kcl/src/lsp/kcl/mod.rs | 73 ++---- src/wasm-lib/kcl/src/lsp/test_util.rs | 1 - src/wasm-lib/kcl/src/test_server.rs | 5 +- .../kw_fn_too_few_args/execution_error.snap | 5 +- src/wasm-lib/src/wasm.rs | 104 ++------ src/wasm-lib/tests/executor/cache.rs | 45 +--- src/wasm-lib/tests/modify/main.rs | 2 +- 26 files changed, 304 insertions(+), 427 deletions(-) diff --git a/src/wasm-lib/derive-docs/src/lib.rs b/src/wasm-lib/derive-docs/src/lib.rs index 3fbfd8043f..d832b7435a 100644 --- a/src/wasm-lib/derive-docs/src/lib.rs +++ b/src/wasm-lib/derive-docs/src/lib.rs @@ -815,7 +815,7 @@ fn generate_code_block_test(fn_name: &str, code_block: &str, index: usize) -> pr context_type: crate::execution::ContextType::Mock, }; - if let Err(e) = ctx.run(program.into(), &mut crate::ExecState::new(&ctx.settings)).await { + if let Err(e) = ctx.run(&program, &mut crate::ExecState::new(&ctx.settings)).await { return Err(miette::Report::new(crate::errors::Report { error: e, filename: format!("{}{}", #fn_name, #index), diff --git a/src/wasm-lib/derive-docs/tests/args_with_lifetime.gen b/src/wasm-lib/derive-docs/tests/args_with_lifetime.gen index 72fbd96b0b..af3d054b33 100644 --- a/src/wasm-lib/derive-docs/tests/args_with_lifetime.gen +++ b/src/wasm-lib/derive-docs/tests/args_with_lifetime.gen @@ -15,7 +15,7 @@ mod test_examples_someFn { context_type: crate::execution::ContextType::Mock, }; if let Err(e) = ctx - .run(program.into(), &mut crate::ExecState::new(&ctx.settings)) + .run(&program, &mut crate::ExecState::new(&ctx.settings)) .await { return Err(miette::Report::new(crate::errors::Report { diff --git a/src/wasm-lib/derive-docs/tests/args_with_refs.gen b/src/wasm-lib/derive-docs/tests/args_with_refs.gen index bfce2913c8..83154f62b4 100644 --- a/src/wasm-lib/derive-docs/tests/args_with_refs.gen +++ b/src/wasm-lib/derive-docs/tests/args_with_refs.gen @@ -15,7 +15,7 @@ mod test_examples_someFn { context_type: crate::execution::ContextType::Mock, }; if let Err(e) = ctx - .run(program.into(), &mut crate::ExecState::new(&ctx.settings)) + .run(&program, &mut crate::ExecState::new(&ctx.settings)) .await { return Err(miette::Report::new(crate::errors::Report { diff --git a/src/wasm-lib/derive-docs/tests/array.gen b/src/wasm-lib/derive-docs/tests/array.gen index 70ce2ee2be..7013206169 100644 --- a/src/wasm-lib/derive-docs/tests/array.gen +++ b/src/wasm-lib/derive-docs/tests/array.gen @@ -16,7 +16,7 @@ mod test_examples_show { context_type: crate::execution::ContextType::Mock, }; if let Err(e) = ctx - .run(program.into(), &mut crate::ExecState::new(&ctx.settings)) + .run(&program, &mut crate::ExecState::new(&ctx.settings)) .await { return Err(miette::Report::new(crate::errors::Report { @@ -73,7 +73,7 @@ mod test_examples_show { context_type: crate::execution::ContextType::Mock, }; if let Err(e) = ctx - .run(program.into(), &mut crate::ExecState::new(&ctx.settings)) + .run(&program, &mut crate::ExecState::new(&ctx.settings)) .await { return Err(miette::Report::new(crate::errors::Report { diff --git a/src/wasm-lib/derive-docs/tests/box.gen b/src/wasm-lib/derive-docs/tests/box.gen index 30df8bb06e..7812a18e5d 100644 --- a/src/wasm-lib/derive-docs/tests/box.gen +++ b/src/wasm-lib/derive-docs/tests/box.gen @@ -16,7 +16,7 @@ mod test_examples_show { context_type: crate::execution::ContextType::Mock, }; if let Err(e) = ctx - .run(program.into(), &mut crate::ExecState::new(&ctx.settings)) + .run(&program, &mut crate::ExecState::new(&ctx.settings)) .await { return Err(miette::Report::new(crate::errors::Report { diff --git a/src/wasm-lib/derive-docs/tests/doc_comment_with_code.gen b/src/wasm-lib/derive-docs/tests/doc_comment_with_code.gen index 1939b07136..c33cf12564 100644 --- a/src/wasm-lib/derive-docs/tests/doc_comment_with_code.gen +++ b/src/wasm-lib/derive-docs/tests/doc_comment_with_code.gen @@ -17,7 +17,7 @@ mod test_examples_my_func { context_type: crate::execution::ContextType::Mock, }; if let Err(e) = ctx - .run(program.into(), &mut crate::ExecState::new(&ctx.settings)) + .run(&program, &mut crate::ExecState::new(&ctx.settings)) .await { return Err(miette::Report::new(crate::errors::Report { @@ -74,7 +74,7 @@ mod test_examples_my_func { context_type: crate::execution::ContextType::Mock, }; if let Err(e) = ctx - .run(program.into(), &mut crate::ExecState::new(&ctx.settings)) + .run(&program, &mut crate::ExecState::new(&ctx.settings)) .await { return Err(miette::Report::new(crate::errors::Report { diff --git a/src/wasm-lib/derive-docs/tests/lineTo.gen b/src/wasm-lib/derive-docs/tests/lineTo.gen index 5e5b030072..fcdb11665c 100644 --- a/src/wasm-lib/derive-docs/tests/lineTo.gen +++ b/src/wasm-lib/derive-docs/tests/lineTo.gen @@ -17,7 +17,7 @@ mod test_examples_line_to { context_type: crate::execution::ContextType::Mock, }; if let Err(e) = ctx - .run(program.into(), &mut crate::ExecState::new(&ctx.settings)) + .run(&program, &mut crate::ExecState::new(&ctx.settings)) .await { return Err(miette::Report::new(crate::errors::Report { @@ -74,7 +74,7 @@ mod test_examples_line_to { context_type: crate::execution::ContextType::Mock, }; if let Err(e) = ctx - .run(program.into(), &mut crate::ExecState::new(&ctx.settings)) + .run(&program, &mut crate::ExecState::new(&ctx.settings)) .await { return Err(miette::Report::new(crate::errors::Report { diff --git a/src/wasm-lib/derive-docs/tests/min.gen b/src/wasm-lib/derive-docs/tests/min.gen index 891ef69fd5..5c3c1f558d 100644 --- a/src/wasm-lib/derive-docs/tests/min.gen +++ b/src/wasm-lib/derive-docs/tests/min.gen @@ -16,7 +16,7 @@ mod test_examples_min { context_type: crate::execution::ContextType::Mock, }; if let Err(e) = ctx - .run(program.into(), &mut crate::ExecState::new(&ctx.settings)) + .run(&program, &mut crate::ExecState::new(&ctx.settings)) .await { return Err(miette::Report::new(crate::errors::Report { @@ -73,7 +73,7 @@ mod test_examples_min { context_type: crate::execution::ContextType::Mock, }; if let Err(e) = ctx - .run(program.into(), &mut crate::ExecState::new(&ctx.settings)) + .run(&program, &mut crate::ExecState::new(&ctx.settings)) .await { return Err(miette::Report::new(crate::errors::Report { diff --git a/src/wasm-lib/derive-docs/tests/option.gen b/src/wasm-lib/derive-docs/tests/option.gen index cb71948ad8..9323159c56 100644 --- a/src/wasm-lib/derive-docs/tests/option.gen +++ b/src/wasm-lib/derive-docs/tests/option.gen @@ -16,7 +16,7 @@ mod test_examples_show { context_type: crate::execution::ContextType::Mock, }; if let Err(e) = ctx - .run(program.into(), &mut crate::ExecState::new(&ctx.settings)) + .run(&program, &mut crate::ExecState::new(&ctx.settings)) .await { return Err(miette::Report::new(crate::errors::Report { diff --git a/src/wasm-lib/derive-docs/tests/option_input_format.gen b/src/wasm-lib/derive-docs/tests/option_input_format.gen index ef01610da3..e03790be0d 100644 --- a/src/wasm-lib/derive-docs/tests/option_input_format.gen +++ b/src/wasm-lib/derive-docs/tests/option_input_format.gen @@ -16,7 +16,7 @@ mod test_examples_import { context_type: crate::execution::ContextType::Mock, }; if let Err(e) = ctx - .run(program.into(), &mut crate::ExecState::new(&ctx.settings)) + .run(&program, &mut crate::ExecState::new(&ctx.settings)) .await { return Err(miette::Report::new(crate::errors::Report { diff --git a/src/wasm-lib/derive-docs/tests/return_vec_box_sketch.gen b/src/wasm-lib/derive-docs/tests/return_vec_box_sketch.gen index 3c366d6eab..4637940934 100644 --- a/src/wasm-lib/derive-docs/tests/return_vec_box_sketch.gen +++ b/src/wasm-lib/derive-docs/tests/return_vec_box_sketch.gen @@ -16,7 +16,7 @@ mod test_examples_import { context_type: crate::execution::ContextType::Mock, }; if let Err(e) = ctx - .run(program.into(), &mut crate::ExecState::new(&ctx.settings)) + .run(&program, &mut crate::ExecState::new(&ctx.settings)) .await { return Err(miette::Report::new(crate::errors::Report { diff --git a/src/wasm-lib/derive-docs/tests/return_vec_sketch.gen b/src/wasm-lib/derive-docs/tests/return_vec_sketch.gen index 5fd19acebb..a593cc5b48 100644 --- a/src/wasm-lib/derive-docs/tests/return_vec_sketch.gen +++ b/src/wasm-lib/derive-docs/tests/return_vec_sketch.gen @@ -16,7 +16,7 @@ mod test_examples_import { context_type: crate::execution::ContextType::Mock, }; if let Err(e) = ctx - .run(program.into(), &mut crate::ExecState::new(&ctx.settings)) + .run(&program, &mut crate::ExecState::new(&ctx.settings)) .await { return Err(miette::Report::new(crate::errors::Report { diff --git a/src/wasm-lib/derive-docs/tests/show.gen b/src/wasm-lib/derive-docs/tests/show.gen index 99c412663e..8b698d53e7 100644 --- a/src/wasm-lib/derive-docs/tests/show.gen +++ b/src/wasm-lib/derive-docs/tests/show.gen @@ -16,7 +16,7 @@ mod test_examples_show { context_type: crate::execution::ContextType::Mock, }; if let Err(e) = ctx - .run(program.into(), &mut crate::ExecState::new(&ctx.settings)) + .run(&program, &mut crate::ExecState::new(&ctx.settings)) .await { return Err(miette::Report::new(crate::errors::Report { diff --git a/src/wasm-lib/derive-docs/tests/test_args_with_exec_state.gen b/src/wasm-lib/derive-docs/tests/test_args_with_exec_state.gen index 409b870f78..edd01d5b10 100644 --- a/src/wasm-lib/derive-docs/tests/test_args_with_exec_state.gen +++ b/src/wasm-lib/derive-docs/tests/test_args_with_exec_state.gen @@ -15,7 +15,7 @@ mod test_examples_some_function { context_type: crate::execution::ContextType::Mock, }; if let Err(e) = ctx - .run(program.into(), &mut crate::ExecState::new(&ctx.settings)) + .run(&program, &mut crate::ExecState::new(&ctx.settings)) .await { return Err(miette::Report::new(crate::errors::Report { diff --git a/src/wasm-lib/kcl-test-server/src/lib.rs b/src/wasm-lib/kcl-test-server/src/lib.rs index 665ca39bce..7bc907d0e8 100644 --- a/src/wasm-lib/kcl-test-server/src/lib.rs +++ b/src/wasm-lib/kcl-test-server/src/lib.rs @@ -176,8 +176,11 @@ async fn snapshot_endpoint(body: Bytes, ctxt: ExecutorContext) -> Response // Let users know if the test is taking a long time. let (done_tx, done_rx) = oneshot::channel::<()>(); let timer = time_until(done_rx); - let snapshot = match ctxt.execute_and_prepare_snapshot(program.into(), &mut exec_state).await { - Ok(sn) => sn, + if let Err(e) = ctxt.run(&program, &mut exec_state).await { + return kcl_err(e); + } + let snapshot = match ctxt.prepare_snapshot().await { + Ok(s) => s, Err(e) => return kcl_err(e), }; let _ = done_tx.send(()); diff --git a/src/wasm-lib/kcl-to-core/src/lib.rs b/src/wasm-lib/kcl-to-core/src/lib.rs index 1b14aa1a66..d018b1e4ad 100644 --- a/src/wasm-lib/kcl-to-core/src/lib.rs +++ b/src/wasm-lib/kcl-to-core/src/lib.rs @@ -16,7 +16,7 @@ pub async fn kcl_to_engine_core(code: &str) -> Result { let ctx = ExecutorContext::new_forwarded_mock(Arc::new(Box::new( crate::conn_mock_core::EngineConnection::new(ref_result).await?, ))); - ctx.run(program.into(), &mut ExecState::new(&ctx.settings)).await?; + ctx.run(&program, &mut ExecState::new(&ctx.settings)).await?; let result = result.lock().expect("mutex lock").clone(); Ok(result) diff --git a/src/wasm-lib/kcl/src/execution/cache.rs b/src/wasm-lib/kcl/src/execution/cache.rs index 427d47c7a7..66d0cbf40f 100644 --- a/src/wasm-lib/kcl/src/execution/cache.rs +++ b/src/wasm-lib/kcl/src/execution/cache.rs @@ -1,26 +1,46 @@ //! Functions for helping with caching an ast and finding the parts the changed. -use serde::{Deserialize, Serialize}; +use std::sync::Arc; + +use tokio::sync::RwLock; use crate::{ - execution::ExecState, + execution::{ExecState, ExecutorSettings}, parsing::ast::types::{Node, Program}, walk::Node as WalkNode, }; -use super::ExecutorSettings; +lazy_static::lazy_static! { + /// A static mutable lock for updating the last successful execution state for the cache. + static ref OLD_AST_MEMORY: Arc>> = Default::default(); +} + +/// Read the old ast memory from the lock. +pub(super) async fn read_old_ast_memory() -> Option { + let old_ast = OLD_AST_MEMORY.read().await; + old_ast.clone() +} + +pub(super) async fn write_old_ast_memory(old_state: OldAstState) { + let mut old_ast = OLD_AST_MEMORY.write().await; + *old_ast = Some(old_state); +} + +pub async fn bust_cache() { + let mut old_ast = OLD_AST_MEMORY.write().await; + // Set the cache to None. + *old_ast = None; +} /// Information for the caching an AST and smartly re-executing it if we can. -#[derive(Debug, Clone, Deserialize, Serialize)] -pub struct CacheInformation { - /// The old information. - pub old: Option, - /// The new ast to executed. - pub new_ast: Node, +#[derive(Debug, Clone)] +pub struct CacheInformation<'a> { + pub ast: &'a Node, + pub settings: &'a ExecutorSettings, } /// The old ast and program memory. -#[derive(Debug, Clone, Deserialize, Serialize)] +#[derive(Debug, Clone)] pub struct OldAstState { /// The ast. pub ast: Node, @@ -30,17 +50,8 @@ pub struct OldAstState { pub settings: crate::execution::ExecutorSettings, } -impl From for CacheInformation { - fn from(program: crate::Program) -> Self { - CacheInformation { - old: None, - new_ast: program.ast, - } - } -} - /// The result of a cache check. -#[derive(Debug, Clone, Deserialize, Serialize, PartialEq)] +#[derive(Debug, Clone, PartialEq)] #[allow(clippy::large_enum_variant)] pub(super) enum CacheResult { ReExecute { @@ -60,23 +71,15 @@ pub(super) enum CacheResult { /// /// Returns `None` when there are no changes to the program, i.e. it is /// fully cached. -pub(super) async fn get_changed_program(info: CacheInformation, settings: &ExecutorSettings) -> CacheResult { - let Some(old) = info.old else { - // We have no old info, we need to re-execute the whole thing. - return CacheResult::ReExecute { - clear_scene: true, - program: info.new_ast, - }; - }; - +pub(super) async fn get_changed_program(old: CacheInformation<'_>, new: CacheInformation<'_>) -> CacheResult { // If the settings are different we might need to bust the cache. // We specifically do this before checking if they are the exact same. - if &old.settings != settings { + if old.settings != new.settings { // If the units are different we need to re-execute the whole thing. - if old.settings.units != settings.units { + if old.settings.units != new.settings.units { return CacheResult::ReExecute { clear_scene: true, - program: info.new_ast, + program: new.ast.clone(), }; } @@ -87,12 +90,13 @@ pub(super) async fn get_changed_program(info: CacheInformation, settings: &Execu // If the ASTs are the EXACT same we return None. // We don't even need to waste time computing the digests. - if old.ast == info.new_ast { + if old.ast == new.ast { return CacheResult::NoAction; } - let mut old_ast = old.ast; - let mut new_ast = info.new_ast; + // We have to clone just because the digests are stored inline :-( + let mut old_ast = old.ast.clone(); + let mut new_ast = new.ast.clone(); // The digests should already be computed, but just in case we don't // want to compare against none. @@ -112,10 +116,7 @@ pub(super) async fn get_changed_program(info: CacheInformation, settings: &Execu /// way in which this gets invoked should always be through /// [get_changed_program]. This is purely to contain the logic on /// how we construct a new [CacheResult]. -fn generate_changed_program(old_ast: Node, new_ast: Node) -> CacheResult { - let mut generated_program = new_ast.clone(); - generated_program.body = vec![]; - +fn generate_changed_program(old_ast: Node, mut new_ast: Node) -> CacheResult { if !old_ast.body.iter().zip(new_ast.body.iter()).all(|(old, new)| { let old_node: WalkNode = old.into(); let new_node: WalkNode = new.into(); @@ -158,13 +159,11 @@ fn generate_changed_program(old_ast: Node, new_ast: Node) -> C // Statements up until now are the same, which means this // is a "pure addition" of the remaining slice. - generated_program - .body - .extend_from_slice(&new_ast.body[old_ast.body.len()..]); + new_ast.body = new_ast.body[old_ast.body.len()..].to_owned(); CacheResult::ReExecute { clear_scene: false, - program: generated_program, + program: new_ast, } } std::cmp::Ordering::Equal => { @@ -177,9 +176,11 @@ fn generate_changed_program(old_ast: Node, new_ast: Node) -> C // so but i think many things. This def needs to change // when the code above changes. + new_ast.body = vec![]; + CacheResult::ReExecute { clear_scene: false, - program: generated_program, + program: new_ast, } } } @@ -187,14 +188,11 @@ fn generate_changed_program(old_ast: Node, new_ast: Node) -> C #[cfg(test)] mod tests { - use crate::execution::parse_execute; - use super::*; + use crate::execution::parse_execute; - // Easy case where we have no old ast and memory. - // We need to re-execute everything. #[tokio::test(flavor = "multi_thread")] - async fn test_get_changed_program_no_old_information() { + async fn test_get_changed_program_same_code() { let new = r#"// Remove the end face for the extrusion. firstSketch = startSketchOn('XY') |> startProfileAt([-12, 12], %) @@ -206,52 +204,18 @@ firstSketch = startSketchOn('XY') // Remove the end face for the extrusion. shell({ faces = ['end'], thickness = 0.25 }, firstSketch)"#; + let (program, ctx, _) = parse_execute(new).await.unwrap(); let result = get_changed_program( CacheInformation { - old: None, - new_ast: program.ast.clone(), + ast: &program.ast, + settings: &ctx.settings, }, - &ctx.settings, - ) - .await; - - assert_eq!( - result, - CacheResult::ReExecute { - clear_scene: true, - program: program.ast - } - ); - } - - #[tokio::test(flavor = "multi_thread")] - async fn test_get_changed_program_same_code() { - let new = r#"// Remove the end face for the extrusion. -firstSketch = startSketchOn('XY') - |> startProfileAt([-12, 12], %) - |> line([24, 0], %) - |> line([0, -24], %) - |> line([-24, 0], %) - |> close(%) - |> extrude(6, %) - -// Remove the end face for the extrusion. -shell({ faces = ['end'], thickness = 0.25 }, firstSketch)"#; - - let (program, ctx, exec_state) = parse_execute(new).await.unwrap(); - - let result = get_changed_program( CacheInformation { - old: Some(OldAstState { - ast: program.ast.clone(), - exec_state, - settings: Default::default(), - }), - new_ast: program.ast.clone(), + ast: &program.ast, + settings: &ctx.settings, }, - &ctx.settings, ) .await; @@ -284,20 +248,19 @@ firstSketch = startSketchOn('XY') // Remove the end face for the extrusion. shell({ faces = ['end'], thickness = 0.25 }, firstSketch)"#; - let (program_old, ctx, exec_state) = parse_execute(old).await.unwrap(); + let (program_old, ctx, _) = parse_execute(old).await.unwrap(); let program_new = crate::Program::parse_no_errs(new).unwrap(); let result = get_changed_program( CacheInformation { - old: Some(OldAstState { - ast: program_old.ast.clone(), - exec_state, - settings: Default::default(), - }), - new_ast: program_new.ast.clone(), + ast: &program_old.ast, + settings: &ctx.settings, + }, + CacheInformation { + ast: &program_new.ast, + settings: &ctx.settings, }, - &ctx.settings, ) .await; @@ -330,20 +293,19 @@ firstSketch = startSketchOn('XY') // Remove the end face for the extrusion. shell({ faces = ['end'], thickness = 0.25 }, firstSketch)"#; - let (program, ctx, exec_state) = parse_execute(old).await.unwrap(); + let (program, ctx, _) = parse_execute(old).await.unwrap(); let program_new = crate::Program::parse_no_errs(new).unwrap(); let result = get_changed_program( CacheInformation { - old: Some(OldAstState { - ast: program.ast.clone(), - exec_state, - settings: Default::default(), - }), - new_ast: program_new.ast.clone(), + ast: &program.ast, + settings: &ctx.settings, + }, + CacheInformation { + ast: &program_new.ast, + settings: &ctx.settings, }, - &ctx.settings, ) .await; @@ -376,20 +338,19 @@ firstSketch = startSketchOn('XY') // Remove the end face for the extrusion. shell({ faces = ['end'], thickness = 0.25 }, firstSketch)"#; - let (program, ctx, exec_state) = parse_execute(old).await.unwrap(); + let (program, ctx, _) = parse_execute(old).await.unwrap(); let program_new = crate::Program::parse_no_errs(new).unwrap(); let result = get_changed_program( CacheInformation { - old: Some(OldAstState { - ast: program.ast.clone(), - exec_state, - settings: Default::default(), - }), - new_ast: program_new.ast.clone(), + ast: &program.ast, + settings: &ctx.settings, + }, + CacheInformation { + ast: &program_new.ast, + settings: &ctx.settings, }, - &ctx.settings, ) .await; @@ -411,21 +372,20 @@ firstSketch = startSketchOn('XY') // Remove the end face for the extrusion. shell({ faces = ['end'], thickness = 0.25 }, firstSketch)"#; - let (program, mut ctx, exec_state) = parse_execute(new).await.unwrap(); + let (program, mut ctx, _) = parse_execute(new).await.unwrap(); // Change the settings to cm. ctx.settings.units = crate::UnitLength::Cm; let result = get_changed_program( CacheInformation { - old: Some(OldAstState { - ast: program.ast.clone(), - exec_state, - settings: Default::default(), - }), - new_ast: program.ast.clone(), + ast: &program.ast, + settings: &Default::default(), + }, + CacheInformation { + ast: &program.ast, + settings: &ctx.settings, }, - &ctx.settings, ) .await; @@ -453,21 +413,20 @@ firstSketch = startSketchOn('XY') // Remove the end face for the extrusion. shell({ faces = ['end'], thickness = 0.25 }, firstSketch)"#; - let (program, mut ctx, exec_state) = parse_execute(new).await.unwrap(); + let (program, mut ctx, _) = parse_execute(new).await.unwrap(); // Change the settings. ctx.settings.show_grid = !ctx.settings.show_grid; let result = get_changed_program( CacheInformation { - old: Some(OldAstState { - ast: program.ast.clone(), - exec_state, - settings: Default::default(), - }), - new_ast: program.ast.clone(), + ast: &program.ast, + settings: &Default::default(), + }, + CacheInformation { + ast: &program.ast, + settings: &ctx.settings, }, - &ctx.settings, ) .await; @@ -489,21 +448,20 @@ firstSketch = startSketchOn('XY') // Remove the end face for the extrusion. shell({ faces = ['end'], thickness = 0.25 }, firstSketch)"#; - let (program, mut ctx, exec_state) = parse_execute(new).await.unwrap(); + let (program, mut ctx, _) = parse_execute(new).await.unwrap(); // Change the settings. ctx.settings.highlight_edges = !ctx.settings.highlight_edges; let result = get_changed_program( CacheInformation { - old: Some(OldAstState { - ast: program.ast.clone(), - exec_state, - settings: Default::default(), - }), - new_ast: program.ast.clone(), + ast: &program.ast, + settings: &Default::default(), + }, + CacheInformation { + ast: &program.ast, + settings: &ctx.settings, }, - &ctx.settings, ) .await; diff --git a/src/wasm-lib/kcl/src/execution/mod.rs b/src/wasm-lib/kcl/src/execution/mod.rs index 24ef7ee3fb..439a516603 100644 --- a/src/wasm-lib/kcl/src/execution/mod.rs +++ b/src/wasm-lib/kcl/src/execution/mod.rs @@ -3,6 +3,7 @@ use std::{path::PathBuf, sync::Arc}; use anyhow::Result; +use cache::OldAstState; use indexmap::IndexMap; use kcmc::{ each_cmd as mcmd, @@ -30,6 +31,7 @@ use crate::{ }; pub use artifact::{Artifact, ArtifactCommand, ArtifactGraph, ArtifactId}; +pub use cache::bust_cache; pub use cad_op::Operation; pub use exec_ast::FunctionParam; pub use geometry::*; @@ -39,7 +41,7 @@ pub use state::{ExecState, IdGenerator}; mod annotations; mod artifact; -pub(crate) mod cache; +mod cache; mod cad_op; mod exec_ast; mod geometry; @@ -470,32 +472,117 @@ impl ExecutorContext { ) -> Result<(), KclError> { self.engine .clear_scene(&mut exec_state.global.id_generator, source_range) - .await?; + .await + } + + pub async fn run_mock( + &self, + program: crate::Program, + program_memory_override: Option, + ) -> Result { + assert!(self.is_mock()); + + let mut exec_state = ExecState::new(&self.settings); + if let Some(program_memory_override) = program_memory_override { + exec_state.mod_local.memory = program_memory_override; + } + + self.inner_run(&program.ast, &mut exec_state).await?; + Ok(exec_state.to_wasm_outcome()) + } + + pub async fn run_with_caching(&self, program: crate::Program) -> Result { + assert!(!self.is_mock()); + + let (program, mut exec_state) = if let Some(OldAstState { + ast: old_ast, + exec_state: old_state, + settings: old_settings, + }) = cache::read_old_ast_memory().await + { + let old = CacheInformation { + ast: &old_ast, + settings: &old_settings, + }; + let new = CacheInformation { + ast: &program.ast, + settings: &self.settings, + }; + + // Get the program that actually changed from the old and new information. + let (clear_scene, program) = match cache::get_changed_program(old, new).await { + CacheResult::ReExecute { clear_scene, program } => (clear_scene, program), + CacheResult::ReapplySettings => { + if self + .engine + .reapply_settings(&self.settings, Default::default()) + .await + .is_ok() + { + return Ok(old_state.to_wasm_outcome()); + } + (true, program.ast) + } + CacheResult::NoAction => return Ok(old_state.to_wasm_outcome()), + }; - // We do not create the planes here as the post hook in wasm will do that - // AND if we aren't in wasm it doesn't really matter. - Ok(()) + let exec_state = if clear_scene { + // Pop the execution state, since we are starting fresh. + let mut exec_state = old_state; + exec_state.reset(&self.settings); + + // We don't do this in mock mode since there is no engine connection + // anyways and from the TS side we override memory and don't want to clear it. + self.send_clear_scene(&mut exec_state, Default::default()) + .await + .map_err(KclErrorWithOutputs::no_outputs)?; + + exec_state + } else { + old_state + }; + + (program, exec_state) + } else { + let mut exec_state = ExecState::new(&self.settings); + self.send_clear_scene(&mut exec_state, Default::default()) + .await + .map_err(KclErrorWithOutputs::no_outputs)?; + (program.ast, exec_state) + }; + + let result = self.inner_run(&program, &mut exec_state).await; + + if result.is_err() { + cache::bust_cache().await; + } + + // Throw the error. + result?; + + // Save this as the last successful execution to the cache. + cache::write_old_ast_memory(OldAstState { + ast: program, + exec_state: exec_state.clone(), + settings: self.settings.clone(), + }) + .await; + + Ok(exec_state.to_wasm_outcome()) } /// Perform the execution of a program. /// /// You can optionally pass in some initialization memory for partial /// execution. - pub async fn run(&self, cache_info: CacheInformation, exec_state: &mut ExecState) -> Result<(), KclError> { - self.inner_run(cache_info, exec_state).await?; - Ok(()) - } - - // TODO program.clone().into() - /// Execute the program, then get a PNG screenshot. - pub async fn execute_and_prepare_snapshot( + pub async fn run( &self, - cache_info: CacheInformation, + program: &crate::Program, exec_state: &mut ExecState, - ) -> std::result::Result { - self.inner_run(cache_info, exec_state).await?; - - self.prepare_snapshot().await + ) -> Result, KclError> { + self.run_with_ui_outputs(program, exec_state) + .await + .map_err(|e| e.into()) } /// Perform the execution of a program. @@ -507,70 +594,31 @@ impl ExecutorContext { /// artifact graph. pub async fn run_with_ui_outputs( &self, - cache_info: CacheInformation, + program: &crate::Program, exec_state: &mut ExecState, - ) -> Result<(), KclErrorWithOutputs> { - self.inner_run(cache_info, exec_state).await?; - Ok(()) - } - - /// Perform the execution of a program. Additionally return engine session - /// data. - pub async fn run_with_session_data( - &self, - cache_info: CacheInformation, - exec_state: &mut ExecState, - ) -> Result, KclError> { - self.inner_run(cache_info, exec_state).await.map_err(|e| e.into()) + ) -> Result, KclErrorWithOutputs> { + self.send_clear_scene(exec_state, Default::default()) + .await + .map_err(KclErrorWithOutputs::no_outputs)?; + self.inner_run(&program.ast, exec_state).await } /// Perform the execution of a program. Accept all possible parameters and /// output everything. - /// - /// You can optionally pass in some initialization memory for partial - /// execution. async fn inner_run( &self, - cache_info: CacheInformation, + program: &Node, exec_state: &mut ExecState, ) -> Result, KclErrorWithOutputs> { let _stats = crate::log::LogPerfStats::new("Interpretation"); - // Get the program that actually changed from the old and new information. - let (clear_scene, program) = match cache::get_changed_program(cache_info.clone(), &self.settings).await { - CacheResult::ReExecute { clear_scene, program } => (clear_scene, program), - CacheResult::ReapplySettings => { - if self - .engine - .reapply_settings(&self.settings, Default::default()) - .await - .is_ok() - { - return Ok(None); - } - (true, cache_info.new_ast) - } - CacheResult::NoAction => return Ok(None), - }; - - if clear_scene && !self.is_mock() { - // Pop the execution state, since we are starting fresh. - exec_state.reset(&self.settings); - - // We don't do this in mock mode since there is no engine connection - // anyways and from the TS side we override memory and don't want to clear it. - self.send_clear_scene(exec_state, Default::default()) - .await - .map_err(KclErrorWithOutputs::no_outputs)?; - } - // Re-apply the settings, in case the cache was busted. self.engine .reapply_settings(&self.settings, Default::default()) .await .map_err(KclErrorWithOutputs::no_outputs)?; - self.execute_and_build_graph(&program, exec_state).await.map_err(|e| { + self.execute_and_build_graph(program, exec_state).await.map_err(|e| { KclErrorWithOutputs::new( e, exec_state.mod_local.operations.clone(), @@ -626,7 +674,7 @@ impl ExecutorContext { } /// Get a snapshot of the current scene. - async fn prepare_snapshot(&self) -> std::result::Result { + pub async fn prepare_snapshot(&self) -> std::result::Result { // Zoom to fit. self.engine .send_modeling_cmd( @@ -682,7 +730,7 @@ async fn parse_execute(code: &str) -> Result<(crate::Program, ExecutorContext, E context_type: ContextType::Mock, }; let mut exec_state = ExecState::new(&ctx.settings); - ctx.run(program.clone().into(), &mut exec_state).await?; + ctx.run(&program, &mut exec_state).await?; Ok((program, ctx, exec_state)) } @@ -1491,16 +1539,17 @@ let w = f() + f() .await .unwrap(); let old_program = crate::Program::parse_no_errs(code).unwrap(); + // Execute the program. - let mut exec_state = ExecState::new(&ctx.settings); - let cache_info = crate::CacheInformation { - old: None, - new_ast: old_program.ast.clone(), - }; - ctx.run(cache_info, &mut exec_state).await.unwrap(); + ctx.run_with_caching(old_program).await.unwrap(); // Get the id_generator from the first execution. - let id_generator = exec_state.global.id_generator.clone(); + let id_generator = cache::read_old_ast_memory() + .await + .unwrap() + .exec_state + .global + .id_generator; let code = r#"sketch001 = startSketchOn('XZ') |> startProfileAt([62.74, 206.13], %) @@ -1518,17 +1567,16 @@ let w = f() + f() // Execute a slightly different program again. let program = crate::Program::parse_no_errs(code).unwrap(); - let cache_info = crate::CacheInformation { - old: Some(crate::OldAstState { - ast: old_program.ast.clone(), - exec_state: exec_state.clone(), - settings: ctx.settings.clone(), - }), - new_ast: program.ast.clone(), - }; // Execute the program. - ctx.run(cache_info, &mut exec_state).await.unwrap(); + ctx.run_with_caching(program).await.unwrap(); + + let new_id_generator = cache::read_old_ast_memory() + .await + .unwrap() + .exec_state + .global + .id_generator; - assert_eq!(id_generator, exec_state.global.id_generator); + assert_eq!(id_generator, new_id_generator); } } diff --git a/src/wasm-lib/kcl/src/lib.rs b/src/wasm-lib/kcl/src/lib.rs index 00ce5e7f49..6f8d8b5f86 100644 --- a/src/wasm-lib/kcl/src/lib.rs +++ b/src/wasm-lib/kcl/src/lib.rs @@ -82,10 +82,7 @@ mod wasm; pub use coredump::CoreDump; pub use engine::{EngineManager, ExecutionKind}; pub use errors::{CompilationError, ConnectionError, ExecError, KclError, KclErrorWithOutputs}; -pub use execution::{ - cache::{CacheInformation, OldAstState}, - ExecState, ExecutorContext, ExecutorSettings, Point2d, -}; +pub use execution::{bust_cache, ExecOutcome, ExecState, ExecutorContext, ExecutorSettings, Point2d}; pub use lsp::{ copilot::Backend as CopilotLspBackend, kcl::{Backend as KclLspBackend, Server as KclLspServerSubCommand}, diff --git a/src/wasm-lib/kcl/src/lsp/kcl/mod.rs b/src/wasm-lib/kcl/src/lsp/kcl/mod.rs index 0c253ebcde..d1f8006eb0 100644 --- a/src/wasm-lib/kcl/src/lsp/kcl/mod.rs +++ b/src/wasm-lib/kcl/src/lsp/kcl/mod.rs @@ -49,7 +49,7 @@ use crate::{ token::TokenStream, PIPE_OPERATOR, }, - CacheInformation, ExecState, ModuleId, OldAstState, Program, SourceRange, + ModuleId, Program, SourceRange, }; const SEMANTIC_TOKEN_TYPES: [SemanticTokenType; 10] = [ SemanticTokenType::NUMBER, @@ -102,12 +102,6 @@ pub struct Backend { pub(super) token_map: DashMap, /// AST maps. pub ast_map: DashMap>, - /// Last successful execution. - /// This gets set to None when execution errors, or we want to bust the cache on purpose to - /// force a re-execution. - /// We do not need to manually bust the cache for changed units, that's handled by the cache - /// information. - pub last_successful_ast_state: Arc>>, /// Memory maps. pub memory_map: DashMap, /// Current code. @@ -192,7 +186,6 @@ impl Backend { diagnostics_map: Default::default(), symbols_map: Default::default(), semantic_tokens_map: Default::default(), - last_successful_ast_state: Default::default(), is_initialized: Default::default(), }) } @@ -267,10 +260,7 @@ impl crate::lsp::backend::Backend for Backend { async fn inner_on_change(&self, params: TextDocumentItem, force: bool) { if force { - // Bust the execution cache. - let mut old_ast_state = self.last_successful_ast_state.write().await; - *old_ast_state = None; - drop(old_ast_state); + crate::bust_cache().await; } let filename = params.uri.to_string(); @@ -688,52 +678,27 @@ impl Backend { return Ok(()); } - let mut last_successful_ast_state = self.last_successful_ast_state.write().await; - - let mut exec_state = if let Some(last_successful_ast_state) = last_successful_ast_state.clone() { - last_successful_ast_state.exec_state - } else { - ExecState::new(&executor_ctx.settings) - }; + match executor_ctx.run_with_caching(ast.clone()).await { + Err(err) => { + self.memory_map.remove(params.uri.as_str()); + self.add_to_diagnostics(params, &[err.error], false).await; - if let Err(err) = executor_ctx - .run( - CacheInformation { - old: last_successful_ast_state.clone(), - new_ast: ast.ast.clone(), - }, - &mut exec_state, - ) - .await - { - self.memory_map.remove(params.uri.as_str()); - self.add_to_diagnostics(params, &[err], false).await; + // Since we already published the diagnostics we don't really care about the error + // string. + Err(anyhow::anyhow!("failed to execute code")) + } + Ok(outcome) => { + let memory = outcome.memory; + self.memory_map.insert(params.uri.to_string(), memory.clone()); - // Update the last successful ast state to be None. - *last_successful_ast_state = None; + // Send the notification to the client that the memory was updated. + self.client + .send_notification::(memory) + .await; - // Since we already published the diagnostics we don't really care about the error - // string. - return Err(anyhow::anyhow!("failed to execute code")); + Ok(()) + } } - - // Update the last successful ast state. - *last_successful_ast_state = Some(OldAstState { - ast: ast.ast.clone(), - exec_state: exec_state.clone(), - settings: executor_ctx.settings.clone(), - }); - drop(last_successful_ast_state); - - self.memory_map - .insert(params.uri.to_string(), exec_state.memory().clone()); - - // Send the notification to the client that the memory was updated. - self.client - .send_notification::(exec_state.mod_local.memory) - .await; - - Ok(()) } pub fn get_semantic_token_type_index(&self, token_type: &SemanticTokenType) -> Option { diff --git a/src/wasm-lib/kcl/src/lsp/test_util.rs b/src/wasm-lib/kcl/src/lsp/test_util.rs index 3450743a4c..ff5c8e69b7 100644 --- a/src/wasm-lib/kcl/src/lsp/test_util.rs +++ b/src/wasm-lib/kcl/src/lsp/test_util.rs @@ -37,7 +37,6 @@ pub async fn kcl_lsp_server(execute: bool) -> Result { can_send_telemetry: true, executor_ctx: Arc::new(tokio::sync::RwLock::new(executor_ctx)), can_execute: Arc::new(tokio::sync::RwLock::new(can_execute)), - last_successful_ast_state: Default::default(), is_initialized: Default::default(), }) .custom_method("kcl/updateUnits", crate::lsp::kcl::Backend::update_units) diff --git a/src/wasm-lib/kcl/src/test_server.rs b/src/wasm-lib/kcl/src/test_server.rs index 5ea84379b8..e9d82c2bf4 100644 --- a/src/wasm-lib/kcl/src/test_server.rs +++ b/src/wasm-lib/kcl/src/test_server.rs @@ -67,8 +67,11 @@ async fn do_execute_and_snapshot( program: Program, ) -> Result<(ExecState, image::DynamicImage), ExecErrorWithState> { let mut exec_state = ExecState::new(&ctx.settings); + ctx.run_with_ui_outputs(&program, &mut exec_state) + .await + .map_err(|err| ExecErrorWithState::new(err.into(), exec_state.clone()))?; let snapshot_png_bytes = ctx - .execute_and_prepare_snapshot(program.into(), &mut exec_state) + .prepare_snapshot() .await .map_err(|err| ExecErrorWithState::new(err, exec_state.clone()))? .contents diff --git a/src/wasm-lib/kcl/tests/kw_fn_too_few_args/execution_error.snap b/src/wasm-lib/kcl/tests/kw_fn_too_few_args/execution_error.snap index 0f811ae264..6932ee48d6 100644 --- a/src/wasm-lib/kcl/tests/kw_fn_too_few_args/execution_error.snap +++ b/src/wasm-lib/kcl/tests/kw_fn_too_few_args/execution_error.snap @@ -1,12 +1,11 @@ --- source: kcl/src/simulation_tests.rs description: Error from executing kw_fn_too_few_args.kcl -snapshot_kind: text --- KCL Semantic error - × semantic: This function requires a parameter y, but you haven't passed - │ it one. + × semantic: This function requires a parameter y, but you haven't passed it + │ one. ╭─[1:7] 1 │ ╭─▶ fn add(x, y) { 2 │ │ return x + y diff --git a/src/wasm-lib/src/wasm.rs b/src/wasm-lib/src/wasm.rs index 9f5e6e638d..98f0f8a8a8 100644 --- a/src/wasm-lib/src/wasm.rs +++ b/src/wasm-lib/src/wasm.rs @@ -4,33 +4,10 @@ use std::sync::Arc; use futures::stream::TryStreamExt; use gloo_utils::format::JsValueSerdeExt; -use kcl_lib::{ - exec::IdGenerator, CacheInformation, CoreDump, EngineManager, ExecState, ModuleId, OldAstState, Point2d, Program, -}; -use tokio::sync::RwLock; +use kcl_lib::{bust_cache, exec::IdGenerator, CoreDump, EngineManager, ModuleId, Point2d, Program}; use tower_lsp::{LspService, Server}; use wasm_bindgen::prelude::*; -lazy_static::lazy_static! { - /// A static mutable lock for updating the last successful execution state for the cache. - static ref OLD_AST_MEMORY: Arc>> = Default::default(); -} - -// Read the old ast memory from the lock, this should never fail since -// in failure scenarios we should just bust the cache and send back None as the previous -// state. -async fn read_old_ast_memory() -> Option { - let lock = OLD_AST_MEMORY.read().await; - lock.clone() -} - -async fn bust_cache() { - // We don't use the cache in mock mode. - let mut current_cache = OLD_AST_MEMORY.write().await; - // Set the cache to None. - *current_cache = None; -} - // wasm_bindgen wrapper for clearing the scene and busting the cache. #[wasm_bindgen] pub async fn clear_scene_and_bust_cache( @@ -38,7 +15,6 @@ pub async fn clear_scene_and_bust_cache( ) -> Result<(), String> { console_error_panic_hook::set_once(); - // Bust the cache. bust_cache().await; let engine = kcl_lib::wasm_engine::EngineConnection::new(engine_manager) @@ -68,69 +44,27 @@ pub async fn execute( let program: Program = serde_json::from_str(program_ast_json).map_err(|e| e.to_string())?; let program_memory_override: Option = serde_json::from_str(program_memory_override_str).map_err(|e| e.to_string())?; + let settings: kcl_lib::Configuration = serde_json::from_str(settings).map_err(|e| e.to_string())?; // If we have a program memory override, assume we are in mock mode. // You cannot override the memory in non-mock mode. - let is_mock = program_memory_override.is_some(); - - let settings: kcl_lib::Configuration = serde_json::from_str(settings).map_err(|e| e.to_string())?; - let ctx = if is_mock { - kcl_lib::ExecutorContext::new_mock(fs_manager, settings.into()).await? - } else { - kcl_lib::ExecutorContext::new(engine_manager, fs_manager, settings.into()).await? - }; - - let mut exec_state = ExecState::new(&ctx.settings); - let mut old_ast_memory = None; - - // Populate from the old exec state if it exists. - if let Some(program_memory_override) = program_memory_override { - // We are in mock mode, so don't use any cache. - exec_state.mod_local.memory = program_memory_override; - } else { - // If we are in mock mode, we don't want to use any cache. - if let Some(old) = read_old_ast_memory().await { - exec_state = old.exec_state.clone(); - old_ast_memory = Some(old); + if program_memory_override.is_some() { + let ctx = kcl_lib::ExecutorContext::new_mock(fs_manager, settings.into()).await?; + match ctx.run_mock(program, program_memory_override).await { + // The serde-wasm-bindgen does not work here because of weird HashMap issues. + // DO NOT USE serde_wasm_bindgen::to_value it will break the frontend. + Ok(outcome) => JsValue::from_serde(&outcome).map_err(|e| e.to_string()), + Err(err) => Err(serde_json::to_string(&err).map_err(|serde_err| serde_err.to_string())?), } - } - - if let Err(err) = ctx - .run_with_ui_outputs( - CacheInformation { - old: old_ast_memory, - new_ast: program.ast.clone(), - }, - &mut exec_state, - ) - .await - { - if !is_mock { - bust_cache().await; + } else { + let ctx = kcl_lib::ExecutorContext::new(engine_manager, fs_manager, settings.into()).await?; + match ctx.run_with_caching(program).await { + // The serde-wasm-bindgen does not work here because of weird HashMap issues. + // DO NOT USE serde_wasm_bindgen::to_value it will break the frontend. + Ok(outcome) => JsValue::from_serde(&outcome).map_err(|e| e.to_string()), + Err(err) => Err(serde_json::to_string(&err).map_err(|serde_err| serde_err.to_string())?), } - - // Throw the error. - return Err(serde_json::to_string(&err).map_err(|serde_err| serde_err.to_string())?); } - - if !is_mock { - // We don't use the cache in mock mode. - let mut current_cache = OLD_AST_MEMORY.write().await; - - // If we aren't in mock mode, save this as the last successful execution to the cache. - *current_cache = Some(OldAstState { - ast: program.ast.clone(), - exec_state: exec_state.clone(), - settings: ctx.settings.clone(), - }); - drop(current_cache); - } - - // The serde-wasm-bindgen does not work here because of weird HashMap issues so we use the - // gloo-serialize crate instead. - // DO NOT USE serde_wasm_bindgen::to_value(&exec_state).map_err(|e| e.to_string()) - // it will break the frontend. - JsValue::from_serde(&exec_state.to_wasm_outcome()).map_err(|e| e.to_string()) } // wasm_bindgen wrapper for execute @@ -153,7 +87,6 @@ pub async fn make_default_planes( engine_manager: kcl_lib::wasm_engine::EngineCommandManager, ) -> Result { console_error_panic_hook::set_once(); - // deserialize the ast from a stringified json let engine = kcl_lib::wasm_engine::EngineConnection::new(engine_manager) .await @@ -163,12 +96,9 @@ pub async fn make_default_planes( .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. JsValue::from_serde(&default_planes).map_err(|e| e.to_string()) } -// wasm_bindgen wrapper for execute #[wasm_bindgen] pub async fn modify_ast_for_sketch_wasm( manager: kcl_lib::wasm_engine::EngineCommandManager, @@ -201,8 +131,6 @@ pub async fn modify_ast_for_sketch_wasm( .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. JsValue::from_serde(&program).map_err(|e| e.to_string()) } diff --git a/src/wasm-lib/tests/executor/cache.rs b/src/wasm-lib/tests/executor/cache.rs index 19d61d732a..830831d6c5 100644 --- a/src/wasm-lib/tests/executor/cache.rs +++ b/src/wasm-lib/tests/executor/cache.rs @@ -1,7 +1,7 @@ //! Cache testing framework. use anyhow::Result; -use kcl_lib::{ExecError, ExecState}; +use kcl_lib::{bust_cache, ExecError, ExecOutcome}; #[derive(Debug)] struct Variation<'a> { @@ -12,15 +12,14 @@ struct Variation<'a> { async fn cache_test( test_name: &str, variations: Vec>, -) -> Result> { +) -> Result> { let first = variations .first() .ok_or_else(|| anyhow::anyhow!("No variations provided for test '{}'", test_name))?; let mut ctx = kcl_lib::ExecutorContext::new_with_client(first.settings.clone(), None, None).await?; - let mut exec_state = kcl_lib::ExecState::new(&ctx.settings); - let mut old_ast_state = None; + bust_cache().await; let mut img_results = Vec::new(); for (index, variation) in variations.iter().enumerate() { let program = kcl_lib::Program::parse_no_errs(variation.code)?; @@ -28,17 +27,8 @@ async fn cache_test( // set the new settings. ctx.settings = variation.settings.clone(); - let snapshot_png_bytes = ctx - .execute_and_prepare_snapshot( - kcl_lib::CacheInformation { - old: old_ast_state, - new_ast: program.ast.clone(), - }, - &mut exec_state, - ) - .await? - .contents - .0; + let outcome = ctx.run_with_caching(program).await?; + let snapshot_png_bytes = ctx.prepare_snapshot().await?.contents.0; // Decode the snapshot, return it. let img = image::ImageReader::new(std::io::Cursor::new(snapshot_png_bytes)) @@ -48,14 +38,7 @@ async fn cache_test( // Save the snapshot. let path = crate::assert_out(&format!("cache_{}_{}", test_name, index), &img); - img_results.push((path, img, exec_state.clone())); - - // Prepare the last state. - old_ast_state = Some(kcl_lib::OldAstState { - ast: program.ast, - exec_state: exec_state.clone(), - settings: variation.settings.clone(), - }); + img_results.push((path, img, outcome)); } ctx.close().await; @@ -256,19 +239,13 @@ extrude(4, sketch001) .await .unwrap(); - let first = result.first().unwrap(); - let second = result.last().unwrap(); + let first = result.first().unwrap().2.artifact_commands.len(); + let second = result.last().unwrap().2.artifact_commands.len(); assert!( - first.2.global.artifact_commands.len() < second.2.global.artifact_commands.len(), + first < second, "Second should have all the artifact commands of the first, plus more. first={:?}, second={:?}", - first.2.global.artifact_commands.len(), - second.2.global.artifact_commands.len() - ); - assert!( - first.2.global.artifact_responses.len() < second.2.global.artifact_responses.len(), - "Second should have all the artifact responses of the first, plus more. first={:?}, second={:?}", - first.2.global.artifact_responses.len(), - second.2.global.artifact_responses.len() + first, + second ); } diff --git a/src/wasm-lib/tests/modify/main.rs b/src/wasm-lib/tests/modify/main.rs index 375e9959d0..0e3079a08f 100644 --- a/src/wasm-lib/tests/modify/main.rs +++ b/src/wasm-lib/tests/modify/main.rs @@ -11,7 +11,7 @@ async fn setup(code: &str, name: &str) -> Result<(ExecutorContext, Program, Modu let program = Program::parse_no_errs(code)?; let ctx = kcl_lib::ExecutorContext::new_with_default_client(Default::default()).await?; let mut exec_state = ExecState::new(&ctx.settings); - ctx.run(program.clone().into(), &mut exec_state).await?; + ctx.run(&program, &mut exec_state).await?; // We need to get the sketch ID. // Get the sketch ID from memory.