diff --git a/.jules/bolt.md b/.jules/bolt.md index 7ca76c16..c69eca92 100644 --- a/.jules/bolt.md +++ b/.jules/bolt.md @@ -53,3 +53,6 @@ ## 2024-05-24 - CI formatting issue **Learning:** cargo fmt needs to run locally before commits to avoid CI formatting errors. **Action:** Always include a cargo fmt --all step in execution plans before submitting. +## 2024-05-24 - Canvas Property Extraction Optimization +**Learning:** Extracting properties from the `RuntimeValue` DSL property lists in `canvas.rs` was inefficient because the code called `.iter().find()` multiple times for each property. In `stdlib/src/web.rs`, a similar pattern was found where `.iter().find()` was called multiple times on `dsl.properties` for elements like "button", "link", "input", and "start". +**Action:** Replace multiple `.find()` calls with a single-pass `for p in &dsl.properties` loop and `match` or `if` statements on the property names, mutating local fallback variables. This reduces time complexity from O(N^2) to O(N) per block. diff --git a/stdlib/src/web.rs b/stdlib/src/web.rs index 54bbd2c1..36ed5618 100644 --- a/stdlib/src/web.rs +++ b/stdlib/src/web.rs @@ -263,30 +263,39 @@ fn dsl_to_html_inner(val: &RuntimeValue, html: &mut String) { render_card(html, dsl); } "button" => { - let label = dsl - .properties - .iter() - .find(|p| p.name == "label") - .and_then(|p| p.value.as_ref()) - .map(|v| v.to_string()) - .unwrap_or_else(|| "Button".to_string()); + let mut label_val = None; + for p in &dsl.properties { + if p.name == "label" { + label_val = p.value.as_ref().map(|v| v.to_string()); + break; + } + } + let label = label_val.unwrap_or_else(|| "Button".to_string()); let _ = write!(html, "", label); } "link" => { - let label = dsl - .properties - .iter() - .find(|p| p.name == "label") - .and_then(|p| p.value.as_ref()) - .map(|v| v.to_string()) - .unwrap_or_else(|| "Link".to_string()); - let url = dsl - .properties - .iter() - .find(|p| p.name == "url") - .and_then(|p| p.value.as_ref()) - .map(|v| v.to_string()); - if let Some(u) = url { + let mut label_val = None; + let mut url_val = None; + for p in &dsl.properties { + match p.name.as_str() { + "label" => { + if label_val.is_none() { + label_val = p.value.as_ref().map(|v| v.to_string()); + } + } + "url" => { + if url_val.is_none() { + url_val = p.value.as_ref().map(|v| v.to_string()); + } + } + _ => {} + } + if label_val.is_some() && url_val.is_some() { + break; + } + } + let label = label_val.unwrap_or_else(|| "Link".to_string()); + if let Some(u) = url_val { let _ = write!(html, "{}", u, label); } else { let _ = write!(html, "{}", label); @@ -322,13 +331,14 @@ fn dsl_to_html_inner(val: &RuntimeValue, html: &mut String) { html.push_str(""); } "input" => { - let placeholder = dsl - .properties - .iter() - .find(|p| p.name == "placeholder") - .and_then(|p| p.value.as_ref()) - .map(|v| v.to_string()); - if let Some(p) = placeholder { + let mut placeholder_val = None; + for p in &dsl.properties { + if p.name == "placeholder" { + placeholder_val = p.value.as_ref().map(|v| v.to_string()); + break; + } + } + if let Some(p) = placeholder_val { let _ = write!(html, "", p); } else { html.push_str(""); @@ -350,13 +360,14 @@ fn dsl_to_html_inner(val: &RuntimeValue, html: &mut String) { html.push_str(""); } "start" => { - let label = dsl - .properties - .iter() - .find(|p| p.name == "label") - .and_then(|p| p.value.as_ref()) - .map(|v| v.to_string()) - .unwrap_or_else(|| "Get Started".to_string()); + let mut label_val = None; + for p in &dsl.properties { + if p.name == "label" { + label_val = p.value.as_ref().map(|v| v.to_string()); + break; + } + } + let label = label_val.unwrap_or_else(|| "Get Started".to_string()); let _ = write!(html, "{}", label); } _ => {