vize_l2 0.481.0

L2 - the Davinci semantic IR (codename Disegno): the neutral op family every input dialect lowers into
Documentation
//! Deep L2 folio mirroring and printing stay heap-grown on small stacks.

#![expect(clippy::disallowed_macros, reason = "insta and fixtures use format!")]

use vize_l0::dump::{Dump, Mode as DumpMode};
use vize_l0::{Allocator, Box, Span, Vec as ArenaVec};
use vize_l2::dump::Page as L2Page;
use vize_l2::op::{ElementOp, Namespace, Op, Region, TextOp};

const DEPTH: usize = 1_100;
const SMALL_STACK: usize = 256 * 1024;

fn nested_tree<'a>(allocator: &'a Allocator) -> ArenaVec<'a, Op<'a>> {
    let mut ops = ArenaVec::from_iter_in(
        [Op::Text(Box::new_in(
            TextOp {
                content: "x",
                span: Span::new(0, 1),
            },
            &allocator,
        ))],
        &allocator,
    );

    for depth in 0..DEPTH {
        let start = depth as u32;
        let element = Op::Element(Box::new_in(
            ElementOp {
                tag: "div",
                namespace: Namespace::Html,
                attributes: ArenaVec::new_in(&allocator),
                bindings: ArenaVec::new_in(&allocator),
                children: Region { ops },
                span: Span::new(start, start + 1),
            },
            &allocator,
        ));
        ops = ArenaVec::from_iter_in([element], &allocator);
    }

    ops
}

#[test]
fn deep_dump_mirror_count_and_print_survive_small_stack() {
    std::thread::Builder::new()
        .stack_size(SMALL_STACK)
        .spawn(|| {
            let allocator = Allocator::default();
            let ops = nested_tree(&allocator);
            let folio = L2Page::of(&ops);

            assert_eq!(folio.op_count(), DEPTH as u64 + 1);
            let printed = folio.print_to_string(DumpMode::Display);
            let expected_tail = format!("{}ui.text \"x\"\n\n", "  ".repeat(DEPTH));
            assert_eq!(printed.lines().nth(1), Some("ops=1101"));
            assert_eq!(
                printed.get(printed.len() - expected_tail.len()..),
                Some(expected_tail.as_str())
            );
            std::mem::forget(folio);
        })
        .expect("spawn worker thread")
        .join()
        .expect("worker thread finished");
}