cotis-modules-debug 0.1.0-alpha

Record, replay, and isolate Cotis layout and UI declaration pipelines
Documentation
//! [`LayoutManager`] decorator that records layout output.
//!
//! Wrap your layout manager with [`LayoutModuleCapture`] during a record pass (stage 1) to
//! capture the per-frame layout output for JSON persistence via
//! [`store_computed_layout`](../fn.store_computed_layout.html).

use cotis::element_configuring::ConfiguredParentElement;
use cotis::layout::{LayoutFrameManager, LayoutManager, LayoutManagerCompatible};
use serde::Serialize;

/// Wraps a layout manager and accumulates layout output across frames.
///
/// Implements [`LayoutManager`] and
/// [`LayoutManagerCompatible`], delegating all
/// operations to the inner module while copying each frame's output into an internal
/// vector accessible via [`output`](Self::output).
///
/// # Recommended usage
///
/// Use for **single-frame capture**: run one `compute_frame`, then call
/// [`store_computed_layout`](../fn.store_computed_layout.html) with `output()`.
///
/// If used across multiple frames, `output()` grows unbounded — each frame's results are
/// appended. There is no automatic reset; avoid multi-frame capture unless you manage the
/// accumulated vector explicitly.
pub struct LayoutModuleCapture<Module, ElementsOutput: Clone + Serialize> {
    internal: Module,
    output: Vec<ElementsOutput>,
}

impl<Module, ElementsOutput: Clone + Serialize> LayoutModuleCapture<Module, ElementsOutput> {
    /// Creates a capture wrapper around an existing layout manager.
    pub fn new(internal: Module) -> Self {
        Self {
            internal,
            output: Vec::new(),
        }
    }

    /// Returns all layout output accumulated so far across every captured frame.
    pub fn output(&self) -> &Vec<ElementsOutput> {
        &self.output
    }
}

struct LayoutModuleFrameCapture<'layout, ElementsOutput, T> {
    output: &'layout mut Vec<ElementsOutput>,
    frame_manager: T,
}

impl<Module, ElementsOutput: Clone + Serialize, Render> LayoutManagerCompatible<Render>
    for LayoutModuleCapture<Module, ElementsOutput>
where
    Module: LayoutManagerCompatible<Render>,
{
    fn init(&mut self, renderer: &mut Render) {
        self.internal.init(renderer);
    }
    fn prepare(&mut self, render: &Render) {
        self.internal.prepare(render);
    }
}

impl<'frame, Module, ElementsOutput: 'frame + Clone + Serialize, ConfigType: 'frame>
    LayoutManager<'frame, ConfigType, ElementsOutput>
    for LayoutModuleCapture<Module, ElementsOutput>
where
    Module: LayoutManager<'frame, ConfigType, ElementsOutput>,
{
    type ElementConfigurer<'layout>
        = Module::ElementConfigurer<'layout>
    where
        Self: 'layout,
        ConfigType: 'frame,
        ElementsOutput: 'frame;

    fn begin_frame<'layout>(
        &'layout mut self,
    ) -> impl LayoutFrameManager<'frame, ConfigType, ElementsOutput, Self::ElementConfigurer<'layout>>
    where
        Self: 'layout,
        ConfigType: 'frame,
        ElementsOutput: 'frame,
    {
        let manager = self.internal.begin_frame();
        LayoutModuleFrameCapture {
            output: &mut self.output,
            frame_manager: manager,
        }
    }
}

impl<'frame, ConfigType: 'frame, ElementsOutput: 'frame + Clone + Serialize, ElementConfigurer, T>
    LayoutFrameManager<'frame, ConfigType, ElementsOutput, ElementConfigurer>
    for LayoutModuleFrameCapture<'_, ElementsOutput, T>
where
    T: LayoutFrameManager<'frame, ConfigType, ElementsOutput, ElementConfigurer>,
    ElementConfigurer: cotis::element_configuring::ConfigureElements<ConfigType>,
{
    fn begin(&'_ mut self) -> ConfiguredParentElement<'_, ElementConfigurer, ConfigType> {
        self.frame_manager.begin()
    }

    fn end(self) -> impl Iterator<Item = ElementsOutput> {
        let iter_output = self.frame_manager.end().collect::<Vec<_>>();
        self.output.append(&mut iter_output.clone());
        iter_output.into_iter()
    }
}