y-engine 0.1.0

A micro-engine that handles boilerplate (winit, wgpu, etc.) and adds quality-of-life features for easy application setup.
Documentation
use app::App;
use state::{running, State};
use winit::{
    application::ApplicationHandler,
    event::WindowEvent,
    event_loop::{ActiveEventLoop, EventLoop},
    window::WindowId,
};

pub mod app;
pub mod state;
pub mod util;

pub struct YEngine<T: App + 'static> {
    inner: Option<YEngineInner<T>>,
}

impl<T: App> ApplicationHandler for YEngine<T> {
    fn resumed(&mut self, event_loop: &ActiveEventLoop) {
        if self.inner.is_none() {
            self.inner = Some(YEngineInner::new(event_loop));
        }
    }

    fn window_event(&mut self, event_loop: &ActiveEventLoop, _: WindowId, event: WindowEvent) {
        if let Some(inner) = self.inner.as_mut() {
            inner.handle_window_event(event_loop, event);
        }
    }
}

impl<T: App + 'static> Default for YEngine<T> {
    fn default() -> Self {
        Self::new()
    }
}

impl<T: App + 'static> YEngine<T> {
    pub fn new() -> Self {
        Self { inner: None }
    }

    pub fn run(&mut self) {
        let event_loop = EventLoop::new().unwrap();
        event_loop.run_app(self).unwrap();
    }
}

struct YEngineInner<T: App + 'static> {
    state: state::State,
    phantom: std::marker::PhantomData<T>,
}

impl<T: App> YEngineInner<T> {
    fn new(event_loop: &ActiveEventLoop) -> Self {
        Self {
            state: state::State::new(event_loop),
            phantom: std::marker::PhantomData,
        }
    }

    fn transition_to_running(&mut self) {
        let old_state = std::mem::replace(&mut self.state, state::State::None);
        let State::Starting(starting) = old_state else {
            panic!("Expected starting state");
        };
        self.state = State::Running(running::State::new::<T>(starting));
    }

    fn handle_window_event(&mut self, event_loop: &ActiveEventLoop, event: WindowEvent) {
        if let State::Starting(state) = &self.state {
            if state.finished() {
                self.transition_to_running();
            }
        }

        self.state.handle_window_event(event_loop, event);
    }
}