mittens-engine 0.7.0

A Vulkan and OpenXR scene engine with ECS, reactive signals, and Meow Meow scripting
use std::sync::{Mutex, OnceLock};

#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub(crate) enum StartupCheckpoint {
    EventLoopResumed = 0,
    WindowCreated = 1,
    RendererInitialized = 2,
    FirstRedrawRequested = 3,
    FirstUpdateCompleted = 4,
    RenderPrepared = 5,
    XrRenderCompleted = 6,
    WindowRenderCompleted = 7,
}

impl StartupCheckpoint {
    const ALL: [StartupCheckpoint; 8] = [
        StartupCheckpoint::EventLoopResumed,
        StartupCheckpoint::WindowCreated,
        StartupCheckpoint::RendererInitialized,
        StartupCheckpoint::FirstRedrawRequested,
        StartupCheckpoint::FirstUpdateCompleted,
        StartupCheckpoint::RenderPrepared,
        StartupCheckpoint::XrRenderCompleted,
        StartupCheckpoint::WindowRenderCompleted,
    ];

    fn label(self) -> &'static str {
        match self {
            StartupCheckpoint::EventLoopResumed => "event loop resumed",
            StartupCheckpoint::WindowCreated => "window created",
            StartupCheckpoint::RendererInitialized => "renderer initialized",
            StartupCheckpoint::FirstRedrawRequested => "first redraw requested",
            StartupCheckpoint::FirstUpdateCompleted => "first update completed",
            StartupCheckpoint::RenderPrepared => "render prepared",
            StartupCheckpoint::XrRenderCompleted => "xr render completed",
            StartupCheckpoint::WindowRenderCompleted => "window render completed",
        }
    }
}

fn progress_state() -> &'static Mutex<Option<StartupCheckpoint>> {
    static STATE: OnceLock<Mutex<Option<StartupCheckpoint>>> = OnceLock::new();
    STATE.get_or_init(|| Mutex::new(None))
}

pub(crate) fn log_startup_progress(checkpoint: StartupCheckpoint) {
    let mut state = progress_state()
        .lock()
        .expect("startup trace mutex poisoned");
    if state.is_some_and(|current| checkpoint <= current) {
        return;
    }

    *state = Some(checkpoint);

    let total = StartupCheckpoint::ALL.len();
    let completed = checkpoint as usize + 1;
    let filled = "".repeat(completed);
    let empty = "".repeat(total.saturating_sub(completed));
    println!(
        "[startup] [{}{}] {}/{} {}",
        filled,
        empty,
        completed,
        total,
        checkpoint.label()
    );
}