Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .jules/bolt.md
Original file line number Diff line number Diff line change
Expand Up @@ -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-09-28 - String Path Borrowing in std.fs Module
**Learning:** Extracting string arguments via `try_into_string()` in standard library callbacks causes unnecessary string cloning and heap allocations even when arguments are already `RuntimeValue::Str`.
**Action:** Borrow `&str` directly from `RuntimeValue::Str` using pattern matching rather than calling `try_into_string()` when passing string path arguments to file I/O operations.
40 changes: 35 additions & 5 deletions stdlib/src/sys.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,21 @@ fn check_fs_capability(ctx: &RuntimeContext) -> Result<(), RuntimeError> {
Ok(())
}

// ⚡ TechScript stdlib execution model is synchronous and native VM function calls return results directly.
// The blocking file I/O operations below are intentional and aligned with TechScript's synchronous stdlib design.
fn sys_read_file(
ctx: &mut RuntimeContext,
args: Vec<RuntimeValue>,
) -> Result<RuntimeValue, RuntimeError> {
check_fs_capability(ctx)?;
let path = args[0].try_into_string()?;
let path_buf;
let path = match &args[0] {
RuntimeValue::Str(s) => s.as_str(),
_ => {
path_buf = args[0].try_into_string()?;
&path_buf
}
};
let content = std::fs::read_to_string(path).map_err(|e| {
RuntimeError::new(
RuntimeErrorKind::InvalidOperation(format!("IO error: {}", e)),
Expand All @@ -41,8 +50,22 @@ fn sys_write_file(
args: Vec<RuntimeValue>,
) -> Result<RuntimeValue, RuntimeError> {
check_fs_capability(ctx)?;
let path = args[0].try_into_string()?;
let content = args[1].try_into_string()?;
let path_buf;
let path = match &args[0] {
RuntimeValue::Str(s) => s.as_str(),
_ => {
path_buf = args[0].try_into_string()?;
&path_buf
}
};
let content_buf;
let content = match &args[1] {
RuntimeValue::Str(s) => s.as_str(),
_ => {
content_buf = args[1].try_into_string()?;
&content_buf
}
};
std::fs::write(path, content).map_err(|e| {
RuntimeError::new(
RuntimeErrorKind::InvalidOperation(format!("IO error: {}", e)),
Expand All @@ -58,8 +81,15 @@ fn sys_exists(
args: Vec<RuntimeValue>,
) -> Result<RuntimeValue, RuntimeError> {
check_fs_capability(ctx)?;
let path = args[0].try_into_string()?;
Ok(RuntimeValue::Bool(std::path::Path::new(&path).exists()))
let path_buf;
let path = match &args[0] {
RuntimeValue::Str(s) => s.as_str(),
_ => {
path_buf = args[0].try_into_string()?;
&path_buf
}
};
Ok(RuntimeValue::Bool(std::path::Path::new(path).exists()))
}

fn sys_now(
Expand Down
50 changes: 50 additions & 0 deletions stdlib/tests/stdlib_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -519,6 +519,7 @@ fn test_http_module() {
let response = "HTTP/1.1 200 OK\r\nContent-Length: 13\r\nContent-Type: text/plain\r\nConnection: close\r\n\r\nHello Server!";
let _ = stream.write_all(response.as_bytes());
let _ = stream.flush();
let _ = stream.shutdown(std::net::Shutdown::Both);
}
});

Expand Down Expand Up @@ -1331,3 +1332,52 @@ fn test_uuid_module() {
assert!(!uuid_str.is_empty());
assert!(uuid_str.contains("-"));
}

#[test]
fn test_sys_read_file_benchmark() {
let registry = StdlibRegistry::new();
let fs = registry.get_module("std.fs").unwrap();

let temp_dir = std::env::temp_dir();
let temp_file = temp_dir.join("techscript_sys_read_bench.txt");
let temp_file_str = temp_file.to_string_lossy().to_string();

let mut caps = HashSet::new();
caps.insert(Capability::FileSystem);
let config = RuntimeConfig {
strict_mode: false,
max_recursion_depth: 1000,
enable_assertions: true,
capabilities: caps,
};
let mut ctx = RuntimeContext::new(config);

let write_file = fs.exports.get("write_file").unwrap();
let read_file = fs.exports.get("read_file").unwrap();

write_file
.call(
&mut ctx,
vec![
RuntimeValue::Str(temp_file_str.clone()),
RuntimeValue::Str("Benchmark test content for sys_read_file".to_string()),
],
)
.unwrap();

let path_val = RuntimeValue::Str(temp_file_str);
let iterations = 10_000;
let start = std::time::Instant::now();

for _ in 0..iterations {
let _ = read_file.call(&mut ctx, vec![path_val.clone()]).unwrap();
}

let elapsed = start.elapsed();
println!(
"\n[BENCHMARK] sys_read_file {} iterations: {:?}",
iterations, elapsed
);

std::fs::remove_file(temp_file).ok();
}
Loading