diff --git a/stdlib/src/canvas.rs b/stdlib/src/canvas.rs index ffcc7a20..248737f3 100644 --- a/stdlib/src/canvas.rs +++ b/stdlib/src/canvas.rs @@ -11,238 +11,298 @@ use techscript_runtime::{ context::{Capability, RuntimeContext}, error::RuntimeError, function::Callable, - value::RuntimeValue, + value::{DslBlockValue, RuntimeValue}, }; /// Convert a DslBlockValue to SVG string. -fn render_dsl_to_svg(svg: &mut String, val: &RuntimeValue, is_dragon: bool) { - match val { - RuntimeValue::DslBlock(dsl) => { - if is_dragon { - match dsl.kind.as_str() { - "logo" => { - 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()) - } - _ => {} - } - } +fn render_circuits(svg: &mut String, dsl: &DslBlockValue, is_dragon: bool) { + if is_dragon { + // Subtle circular grids / tech lines background - 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#"{}"#, - size, color, text - ); - } - "rings" => { - // BLUE FLAME / WING (Bottom-Left Swirl) - svg.push_str( - r##""## - ); - } - "emblem" => { - // ORANGE-RED TAIL (Bottom-Right Swirl) - svg.push_str( - r##" - "## - ); - } - "letter" => { - // GOLDEN DRAGON HEAD (Top-Center Crest) - svg.push_str( - r##" - - "## - ); - } - "circuits" => { - // Subtle circular grids / tech lines background - svg.push_str( - r##" - "## - ); - } - _ => {} - } - } else { - // RENDER OLD GEOMETRIC LOGO - match dsl.kind.as_str() { - "logo" => { - 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()) - } - _ => {} - } - } + svg.push_str( - 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#"{}"#, - size, color, text - ); - } - "rings" => { - 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()) - } - _ => {} - } - } + r##" - 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); - let _ = write!( - svg, - r#""#, - r, color, thickness, opacity - ); - } - } - "emblem" => { - 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!( - svg, - r#""#, - x, - y, - size, - size, - size / 4, - color - ); - } - "letter" => { - 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()) - } - _ => {} - } - } + ); + } else { + let mut color_val = None; - 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#"{}"#, - size, color, ch - ); - } - "core" => { - 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()) - } - _ => {} - } - } + 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(|| "#66e0ff".to_string()); - let size = size_val.unwrap_or(40); - let _ = write!( - svg, - r#""#, - size / 2, - color - ); - } - "circuits" => { - let mut color_val = None; + let color = color_val.unwrap_or_else(|| "#00d4ff".to_string()); - for p in &dsl.properties { - if p.name == "color" { - color_val = p.value.as_ref().map(|v| v.to_string()); - } - } + let _ = write!( + svg, + r#" - let color = color_val.unwrap_or_else(|| "#00d4ff".to_string()); - let _ = write!( - svg, - r#" - - - - - "#, - color, color, color, color, color, color - ); - } - _ => {} + + + + + + + + + "#, + color, color, color, color, color, color + ); + } +} + +fn render_letter(svg: &mut String, dsl: &DslBlockValue, is_dragon: bool) { + if is_dragon { + // GOLDEN DRAGON HEAD (Top-Center Crest) + + svg.push_str( + + r##" + + + + "## + + ); + } else { + 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#"{}"#, + size, color, ch + ); + } +} + +fn render_logo(svg: &mut String, dsl: &DslBlockValue, is_dragon: bool) { + if is_dragon { + 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#"{}"#, + size, color, text + ); + } else { + 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#"{}"#, + size, color, text + ); + } +} + +fn render_core(svg: &mut String, dsl: &DslBlockValue) { + 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#""#, + size / 2, + color + ); +} + +fn render_emblem(svg: &mut String, dsl: &DslBlockValue, is_dragon: bool) { + if is_dragon { + // ORANGE-RED TAIL (Bottom-Right Swirl) + + svg.push_str( + + r##" + + "## + + ); + } else { + 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!( + svg, + r#""#, + x, + y, + size, + size, + size / 4, + color + ); + } +} + +fn render_rings(svg: &mut String, dsl: &DslBlockValue, is_dragon: bool) { + if is_dragon { + // BLUE FLAME / WING (Bottom-Left Swirl) + + svg.push_str( + + r##""## + + ); + } else { + 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); + + let _ = write!( + svg, + r#""#, + r, color, thickness, opacity + ); + } + } +} + +fn render_dsl_to_svg(svg: &mut String, val: &RuntimeValue, is_dragon: bool) { + if let RuntimeValue::DslBlock(dsl) = val { + match dsl.kind.as_str() { + "circuits" => render_circuits(svg, dsl, is_dragon), + "letter" => render_letter(svg, dsl, is_dragon), + "logo" => render_logo(svg, dsl, is_dragon), + "core" => { + if !is_dragon { + render_core(svg, dsl); } } + "emblem" => render_emblem(svg, dsl, is_dragon), + "rings" => render_rings(svg, dsl, is_dragon), + _ => {} } - _ => {} } } diff --git a/stdlib/tests/stdlib_tests.rs b/stdlib/tests/stdlib_tests.rs index ce296064..50a54c49 100644 --- a/stdlib/tests/stdlib_tests.rs +++ b/stdlib/tests/stdlib_tests.rs @@ -540,7 +540,9 @@ fn test_http_module() { &mut ctx_unprivileged, vec![RuntimeValue::Str(format!("http://127.0.0.1:{}", port))], ); - assert!(matches!(res_get, Err(techscript_runtime::RuntimeError { kind: techscript_runtime::RuntimeErrorKind::InvalidOperation(msg), .. }) if msg.contains("Security policy violation"))); + assert!( + matches!(res_get, Err(techscript_runtime::RuntimeError { kind: techscript_runtime::RuntimeErrorKind::InvalidOperation(msg), .. }) if msg.contains("Security policy violation")) + ); let post = http.exports.get("post").unwrap(); let res_post = post.call( @@ -550,7 +552,9 @@ fn test_http_module() { RuntimeValue::Str("body".to_string()), ], ); - assert!(matches!(res_post, Err(techscript_runtime::RuntimeError { kind: techscript_runtime::RuntimeErrorKind::InvalidOperation(msg), .. }) if msg.contains("Security policy violation"))); + assert!( + matches!(res_post, Err(techscript_runtime::RuntimeError { kind: techscript_runtime::RuntimeErrorKind::InvalidOperation(msg), .. }) if msg.contains("Security policy violation")) + ); // Test with Network capability let mut caps = HashSet::new();