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
3 changes: 3 additions & 0 deletions .jules/bolt.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,6 @@
## 2026-09-22 - String allocation optimization in std.web DSL rendering
**Learning:** Generating deep HTML structures in `std.web` heavily penalized performance because `dsl_to_html` allocated and returned a new `String` for every child DSL node. This causes `O(N)` heap allocations and redundant copying in the render tree. By passing a mutable `&mut String` buffer recursively downwards, we avoid all intermediate string heap allocations and significantly improve serialization speed.
**Action:** Always prefer using a recursive builder pattern passing a single mutable `&mut String` buffer to `write!` or `push_str` when rendering nested tree structures (like HTML, JSON, or ASTs) instead of returning newly allocated strings at each layer.
## 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 `logo`, `rings`, `emblem`, `letter`, `core`, and `circuits` definitions.
**Action:** Replace multiple `.find()` calls with a single-pass `for p in &dsl.properties` loop and `match` on the property names, mutating local fallback variables.
245 changes: 119 additions & 126 deletions stdlib/src/canvas.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,27 +21,24 @@ fn render_dsl_to_svg(svg: &mut String, val: &RuntimeValue, is_dragon: bool) {
if is_dragon {
match dsl.kind.as_str() {
"logo" => {
let text = dsl
.properties
.iter()
.find(|p| p.name == "text")
.and_then(|p| p.value.as_ref())
.map(|v| v.to_string())
.unwrap_or_else(|| "Logo".to_string());
let color = dsl
.properties
.iter()
.find(|p| p.name == "color")
.and_then(|p| p.value.as_ref())
.map(|v| v.to_string())
.unwrap_or_else(|| "#00d4ff".to_string());
let size = dsl
.properties
.iter()
.find(|p| p.name == "size")
.and_then(|p| p.value.as_ref())
.and_then(|v| v.try_into_int().ok())
.unwrap_or(48);
let mut text_val = None;
let mut color_val = None;
let mut size_val = None;

for p in &dsl.properties {
match p.name.as_str() {
"text" => text_val = p.value.as_ref().map(|v| v.to_string()),
"color" => color_val = p.value.as_ref().map(|v| v.to_string()),
"size" => {
size_val = p.value.as_ref().and_then(|v| v.try_into_int().ok())
}
_ => {}
}
}

let text = text_val.unwrap_or_else(|| "Logo".to_string());
let color = color_val.unwrap_or_else(|| "#00d4ff".to_string());
let size = size_val.unwrap_or(48);
let _ = write!(
svg,
r#"<text x="250" y="440" text-anchor="middle" dominant-baseline="central" font-size="{}" font-weight="800" fill="{}" font-family="system-ui, -apple-system, sans-serif" letter-spacing="3">{}</text>"#,
Expand Down Expand Up @@ -82,62 +79,57 @@ fn render_dsl_to_svg(svg: &mut String, val: &RuntimeValue, is_dragon: bool) {
// RENDER OLD GEOMETRIC LOGO
match dsl.kind.as_str() {
"logo" => {
let text = dsl
.properties
.iter()
.find(|p| p.name == "text")
.and_then(|p| p.value.as_ref())
.map(|v| v.to_string())
.unwrap_or_else(|| "Logo".to_string());
let color = dsl
.properties
.iter()
.find(|p| p.name == "color")
.and_then(|p| p.value.as_ref())
.map(|v| v.to_string())
.unwrap_or_else(|| "#00d4ff".to_string());
let size = dsl
.properties
.iter()
.find(|p| p.name == "size")
.and_then(|p| p.value.as_ref())
.and_then(|v| v.try_into_int().ok())
.unwrap_or(48);
let mut text_val = None;
let mut color_val = None;
let mut size_val = None;

for p in &dsl.properties {
match p.name.as_str() {
"text" => text_val = p.value.as_ref().map(|v| v.to_string()),
"color" => color_val = p.value.as_ref().map(|v| v.to_string()),
"size" => {
size_val = p.value.as_ref().and_then(|v| v.try_into_int().ok())
}
_ => {}
}
}

let text = text_val.unwrap_or_else(|| "Logo".to_string());
let color = color_val.unwrap_or_else(|| "#00d4ff".to_string());
let size = size_val.unwrap_or(48);
let _ = write!(
svg,
r#"<text x="250" y="380" text-anchor="middle" dominant-baseline="central" font-size="{}" font-weight="800" fill="{}" font-family="system-ui, -apple-system, sans-serif" letter-spacing="3">{}</text>"#,
size, color, text
);
}
"rings" => {
let count = dsl
.properties
.iter()
.find(|p| p.name == "count")
.and_then(|p| p.value.as_ref())
.and_then(|v| v.try_into_int().ok())
.unwrap_or(3);
let color = dsl
.properties
.iter()
.find(|p| p.name == "color")
.and_then(|p| p.value.as_ref())
.map(|v| v.to_string())
.unwrap_or_else(|| "#00d4ff".to_string());
let size = dsl
.properties
.iter()
.find(|p| p.name == "size")
.and_then(|p| p.value.as_ref())
.and_then(|v| v.try_into_int().ok())
.unwrap_or(40);
let thickness = dsl
.properties
.iter()
.find(|p| p.name == "thickness")
.and_then(|p| p.value.as_ref())
.and_then(|v| v.try_into_int().ok())
.unwrap_or(3);
let mut count_val = None;
let mut color_val = None;
let mut size_val = None;
let mut thickness_val = None;

for p in &dsl.properties {
match p.name.as_str() {
"count" => {
count_val = p.value.as_ref().and_then(|v| v.try_into_int().ok())
}
"color" => color_val = p.value.as_ref().map(|v| v.to_string()),
"size" => {
size_val = p.value.as_ref().and_then(|v| v.try_into_int().ok())
}
"thickness" => {
thickness_val =
p.value.as_ref().and_then(|v| v.try_into_int().ok())
}
_ => {}
}
}

let count = count_val.unwrap_or(3);
let color = color_val.unwrap_or_else(|| "#00d4ff".to_string());
let size = size_val.unwrap_or(40);
let thickness = thickness_val.unwrap_or(3);
for i in 0..count {
let r = 80 + i as i64 * (size / 2);
let opacity = 0.4 - (i as f32 * 0.08);
Expand All @@ -149,20 +141,21 @@ fn render_dsl_to_svg(svg: &mut String, val: &RuntimeValue, is_dragon: bool) {
}
}
"emblem" => {
let color = dsl
.properties
.iter()
.find(|p| p.name == "color")
.and_then(|p| p.value.as_ref())
.map(|v| v.to_string())
.unwrap_or_else(|| "#0088cc".to_string());
let size = dsl
.properties
.iter()
.find(|p| p.name == "size")
.and_then(|p| p.value.as_ref())
.and_then(|v| v.try_into_int().ok())
.unwrap_or(120);
let mut color_val = None;
let mut size_val = None;

for p in &dsl.properties {
match p.name.as_str() {
"color" => color_val = p.value.as_ref().map(|v| v.to_string()),
"size" => {
size_val = p.value.as_ref().and_then(|v| v.try_into_int().ok())
}
_ => {}
}
}

let color = color_val.unwrap_or_else(|| "#0088cc".to_string());
let size = size_val.unwrap_or(120);
let x = 250 - size / 2;
let y = 180 - size / 2;
let _ = write!(
Expand All @@ -177,48 +170,46 @@ fn render_dsl_to_svg(svg: &mut String, val: &RuntimeValue, is_dragon: bool) {
);
}
"letter" => {
let ch = dsl
.properties
.iter()
.find(|p| p.name == "char")
.and_then(|p| p.value.as_ref())
.map(|v| v.to_string())
.unwrap_or_else(|| "T".to_string());
let color = dsl
.properties
.iter()
.find(|p| p.name == "color")
.and_then(|p| p.value.as_ref())
.map(|v| v.to_string())
.unwrap_or_else(|| "#0a0e27".to_string());
let size = dsl
.properties
.iter()
.find(|p| p.name == "size")
.and_then(|p| p.value.as_ref())
.and_then(|v| v.try_into_int().ok())
.unwrap_or(32);
let mut ch_val = None;
let mut color_val = None;
let mut size_val = None;

for p in &dsl.properties {
match p.name.as_str() {
"char" => ch_val = p.value.as_ref().map(|v| v.to_string()),
"color" => color_val = p.value.as_ref().map(|v| v.to_string()),
"size" => {
size_val = p.value.as_ref().and_then(|v| v.try_into_int().ok())
}
_ => {}
}
}

let ch = ch_val.unwrap_or_else(|| "T".to_string());
let color = color_val.unwrap_or_else(|| "#0a0e27".to_string());
let size = size_val.unwrap_or(32);
let _ = write!(
svg,
r#"<text x="250" y="180" text-anchor="middle" dominant-baseline="central" font-size="{}" font-weight="900" fill="{}" font-family="system-ui, -apple-system, sans-serif">{}</text>"#,
size, color, ch
);
}
"core" => {
let color = dsl
.properties
.iter()
.find(|p| p.name == "color")
.and_then(|p| p.value.as_ref())
.map(|v| v.to_string())
.unwrap_or_else(|| "#66e0ff".to_string());
let size = dsl
.properties
.iter()
.find(|p| p.name == "size")
.and_then(|p| p.value.as_ref())
.and_then(|v| v.try_into_int().ok())
.unwrap_or(40);
let mut color_val = None;
let mut size_val = None;

for p in &dsl.properties {
match p.name.as_str() {
"color" => color_val = p.value.as_ref().map(|v| v.to_string()),
"size" => {
size_val = p.value.as_ref().and_then(|v| v.try_into_int().ok())
}
_ => {}
}
}

let color = color_val.unwrap_or_else(|| "#66e0ff".to_string());
let size = size_val.unwrap_or(40);
let _ = write!(
svg,
r#"<circle cx="250" cy="180" r="{}" fill="{}" opacity="0.8"/>"#,
Expand All @@ -227,13 +218,15 @@ fn render_dsl_to_svg(svg: &mut String, val: &RuntimeValue, is_dragon: bool) {
);
}
"circuits" => {
let color = dsl
.properties
.iter()
.find(|p| p.name == "color")
.and_then(|p| p.value.as_ref())
.map(|v| v.to_string())
.unwrap_or_else(|| "#00d4ff".to_string());
let mut color_val = None;

for p in &dsl.properties {
if p.name == "color" {
color_val = p.value.as_ref().map(|v| v.to_string());
}
}

let color = color_val.unwrap_or_else(|| "#00d4ff".to_string());
let _ = write!(
svg,
r#"<line x1="50" y1="180" x2="450" y2="180" stroke="{}" stroke-width="1.5" stroke-dasharray="5 5" opacity="0.6"/>
Expand Down
3 changes: 3 additions & 0 deletions test_perf.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
fn main() {
println!("Testing performance...");
}
Loading