cotis-modules-debug 0.1.0-alpha

Record, replay, and isolate Cotis layout and UI declaration pipelines
Documentation
//! Renderer replay wrapper for re-drawing saved render command streams.
//!
//! Use [`RenderModuleReplay`] when you have precomputed render commands **and** need the
//! renderer's `init` hook to run against a live layout manager (for example, to load fonts
//! or textures registered during layout init).
//!
//! For stage 3 when layout output JSON plus a pipe is sufficient and no renderer init from
//! a layout module is needed, prefer calling [`CotisRenderer::draw_frame`]
//! directly (see `gradients_example_solid_render_only`).

use cotis::renders::{CotisRenderer, CotisRendererAsync, RenderCompatibleWith};

/// Thin wrapper around a renderer for debug replay.
pub struct RenderModuleReplay<Renderer> {
    internal: Renderer,
}

impl<Renderer> RenderModuleReplay<Renderer> {
    /// Creates a replay wrapper around an existing renderer.
    pub fn new(renderer: Renderer) -> Self {
        Self { internal: renderer }
    }
}

/// Synchronous renderer replay: `init(layout)` followed by `draw_frame(commands)`.
pub trait RenderModuleReplayTrait<'frame, ConfigType, RenderCommandType, LayoutModule> {
    /// Initializes the renderer against `layout`, then draws `render_commands`.
    fn replay(
        &mut self,
        render_commands: impl Iterator<Item = RenderCommandType>,
        layout: &mut LayoutModule,
    );
}

impl<'frame, ConfigType, RenderCommandType, LayoutModule, Renderer>
    RenderModuleReplayTrait<'frame, ConfigType, RenderCommandType, LayoutModule>
    for RenderModuleReplay<Renderer>
where
    Renderer: RenderCompatibleWith<LayoutModule> + CotisRenderer<RenderCommandType>,
{
    fn replay(
        &mut self,
        render_commands: impl Iterator<Item = RenderCommandType>,
        layout: &mut LayoutModule,
    ) {
        self.internal.init(layout);
        self.internal.draw_frame(render_commands);
    }
}

/// Async renderer replay: `init(layout)` followed by `draw_frame(commands).await`.
#[allow(async_fn_in_trait)]
pub trait RenderModuleReplayAsyncTrait<'frame, ConfigType, RenderCommandType, LayoutModule> {
    /// Initializes the renderer against `layout`, then draws `render_commands` asynchronously.
    async fn replay(
        &mut self,
        render_commands: impl Iterator<Item = RenderCommandType>,
        layout: &mut LayoutModule,
    );
}

impl<'frame, ConfigType, RenderCommandType, LayoutModule, Renderer>
    RenderModuleReplayAsyncTrait<'frame, ConfigType, RenderCommandType, LayoutModule>
    for RenderModuleReplay<Renderer>
where
    Renderer: RenderCompatibleWith<LayoutModule> + CotisRendererAsync<RenderCommandType>,
{
    async fn replay(
        &mut self,
        render_commands: impl Iterator<Item = RenderCommandType>,
        layout: &mut LayoutModule,
    ) {
        self.internal.init(layout);
        self.internal.draw_frame(render_commands).await;
    }
}