icons 0.5.2

Icons for Rust fullstack applications — Leptos and Dioxus.
Documentation
use std::sync::OnceLock;
use std::time::Instant;

use icons::leptos::parser::{SvgElement, parse_svg_elements};

// Test that demonstrates the performance difference
#[test]
fn test_caching_performance_difference() {
    const SVG_CONTENT: &str = r#"<path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/>
<circle cx="12" cy="12" r="3"/>
<rect x="9" y="9" width="6" height="6"/>
<polyline points="11 3 11 11 14 8 17 11 17 3"/>
<polygon points="0,0 5,5 10,0"/>"#;

    const ITERATIONS: usize = 1000;

    // Test parsing every time (old approach)
    let start = Instant::now();
    for _ in 0..ITERATIONS {
        let _elements = parse_svg_elements(SVG_CONTENT);
    }
    let parse_every_time = start.elapsed();

    // Test cached approach
    static CACHE: OnceLock<Vec<SvgElement>> = OnceLock::new();

    let start = Instant::now();
    for _ in 0..ITERATIONS {
        let _elements = CACHE.get_or_init(|| parse_svg_elements(SVG_CONTENT));
    }
    let cached_approach = start.elapsed();

    println!("Parse every time ({} iterations): {:?}", ITERATIONS, parse_every_time);
    println!("Cached approach ({} iterations): {:?}", ITERATIONS, cached_approach);
    println!(
        "Performance improvement: {:.2}x faster",
        parse_every_time.as_nanos() as f64 / cached_approach.as_nanos() as f64
    );

    // The cached approach should be significantly faster for subsequent calls
    assert!(cached_approach < parse_every_time);
}

#[test]
fn test_cache_behavior() {
    const SVG_CONTENT: &str =
        r#"<path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/>"#;

    static TEST_CACHE: OnceLock<Vec<SvgElement>> = OnceLock::new();

    // First call should initialize the cache
    let start = Instant::now();
    let elements1 = TEST_CACHE.get_or_init(|| {
        println!("Cache miss - parsing SVG");
        parse_svg_elements(SVG_CONTENT)
    });
    let first_call_duration = start.elapsed();

    // Subsequent calls should use cached data
    let start = Instant::now();
    let elements2 = TEST_CACHE.get_or_init(|| {
        println!("This should not print - cache should hit");
        parse_svg_elements(SVG_CONTENT)
    });
    let second_call_duration = start.elapsed();

    // Verify same reference (cached)
    assert!(std::ptr::eq(elements1, elements2));

    // Second call should be much faster
    assert!(second_call_duration < first_call_duration);

    println!("First call (parse + cache): {:?}", first_call_duration);
    println!("Second call (cache hit): {:?}", second_call_duration);
    println!(
        "Cache hit speedup: {:.2}x faster",
        first_call_duration.as_nanos() as f64 / second_call_duration.as_nanos() as f64
    );
}

// Test with realistic icon data
#[test]
fn test_realistic_icon_performance() {
    // Use actual icon content similar to what we have
    const ARROW_DOWN_SVG: &str = r#"<path d="m21 16-4 4-4-4"/>
<path d="M21 12H3"/>
<path d="m5 6 4-4 4 4"/>"#;

    static ARROW_CACHE: OnceLock<Vec<SvgElement>> = OnceLock::new();

    // Simulate 100 component renders
    const RENDERS: usize = 100;

    // Without caching (parse every render)
    let start = Instant::now();
    for _ in 0..RENDERS {
        let _elements = parse_svg_elements(ARROW_DOWN_SVG);
    }
    let without_cache = start.elapsed();

    // With caching (parse once, reuse)
    let start = Instant::now();
    for _ in 0..RENDERS {
        let _elements = ARROW_CACHE.get_or_init(|| parse_svg_elements(ARROW_DOWN_SVG));
    }
    let with_cache = start.elapsed();

    let improvement = without_cache.as_nanos() as f64 / with_cache.as_nanos() as f64;

    println!("Realistic icon test ({} renders):", RENDERS);
    println!("  Without cache: {:?}", without_cache);
    println!("  With cache: {:?}", with_cache);
    println!("  Performance gain: {:.2}x faster", improvement);

    // Should show significant improvement
    assert!(improvement > 10.0, "Caching should provide significant speedup");
}