diff --git a/.jules/bolt.md b/.jules/bolt.md index 3faa4acb..b1a0edb5 100644 --- a/.jules/bolt.md +++ b/.jules/bolt.md @@ -70,3 +70,7 @@ ## 2024-05-24 - Web Property Extraction Optimization **Learning:** Extracting properties from the `RuntimeValue` DSL property lists in `stdlib/src/web/renderer.rs` and `stdlib/src/web/db.rs` was inefficient because the code called `.iter().find()` to resolve `text`, `id`, and `name` attributes, which creates unnecessary iterator overhead and closure allocation. **Action:** Replace `.iter().find()` calls with a single-pass `for p in &dsl.properties` loop and `if` statements on the property names, stopping early when found, which significantly reduces execution overhead. + +## 2026-10-28 - Standard Library File Operations String Allocation Optimization +**Learning:** Calling `try_into_string(&self)` on owned `RuntimeValue` arguments in standard library functions like `sys_write_file` and `sys_read_file` clones the string payload, causing redundant string allocations and memory copy overhead for file operations. +**Action:** Provide and use an `into_string(self)` method on `RuntimeValue` when owned arguments are available in standard library callback handlers to extract strings directly without allocation. diff --git a/runtime/runtime/src/value.rs b/runtime/runtime/src/value.rs index b9f91bdc..c5514704 100644 --- a/runtime/runtime/src/value.rs +++ b/runtime/runtime/src/value.rs @@ -212,6 +212,13 @@ impl RuntimeValue { } } + pub fn into_string(self) -> Result { + match self { + Self::Str(s) => Ok(s), + other => Ok(other.to_string()), + } + } + /// Verifies reference identity check (===). pub fn physical_eq(&self, other: &Self) -> bool { match (self, other) { diff --git a/stdlib/src/sys.rs b/stdlib/src/sys.rs index 00a45f14..7fcd2732 100644 --- a/stdlib/src/sys.rs +++ b/stdlib/src/sys.rs @@ -25,7 +25,20 @@ fn sys_read_file( args: Vec, ) -> Result { check_fs_capability(ctx)?; - let path = args[0].try_into_string()?; + let mut args_iter = args.into_iter(); + let path = args_iter + .next() + .ok_or_else(|| { + RuntimeError::new( + RuntimeErrorKind::ArityMismatch { + expected: 1, + found: 0, + }, + None, + None, + ) + })? + .into_string()?; let content = std::fs::read_to_string(path).map_err(|e| { RuntimeError::new( RuntimeErrorKind::InvalidOperation(format!("IO error: {}", e)), @@ -41,8 +54,33 @@ fn sys_write_file( args: Vec, ) -> Result { check_fs_capability(ctx)?; - let path = args[0].try_into_string()?; - let content = args[1].try_into_string()?; + let mut args_iter = args.into_iter(); + let path = args_iter + .next() + .ok_or_else(|| { + RuntimeError::new( + RuntimeErrorKind::ArityMismatch { + expected: 2, + found: 0, + }, + None, + None, + ) + })? + .into_string()?; + let content = args_iter + .next() + .ok_or_else(|| { + RuntimeError::new( + RuntimeErrorKind::ArityMismatch { + expected: 2, + found: 1, + }, + None, + None, + ) + })? + .into_string()?; std::fs::write(path, content).map_err(|e| { RuntimeError::new( RuntimeErrorKind::InvalidOperation(format!("IO error: {}", e)), @@ -58,7 +96,20 @@ fn sys_exists( args: Vec, ) -> Result { check_fs_capability(ctx)?; - let path = args[0].try_into_string()?; + let mut args_iter = args.into_iter(); + let path = args_iter + .next() + .ok_or_else(|| { + RuntimeError::new( + RuntimeErrorKind::ArityMismatch { + expected: 1, + found: 0, + }, + None, + None, + ) + })? + .into_string()?; Ok(RuntimeValue::Bool(std::path::Path::new(&path).exists())) }