rocketsplash-formats 0.3.0

Shared data types and serialization formats for Rocketsplash TUI animations
Documentation
// <FILE>crates/rocketsplash-formats/src/splash.rs</FILE>
// <DESC>Splash screen format definitions and validation</DESC>
// <VERS>VERSION: 2.0.0</VERS>
// <WCTX>Foundation crates 0.3.0 (RELEASE_PLAN D2 typed errors, D3 adversarial hardening)</WCTX>
// <CLOG>2.0.0: validate() returns typed FormatError (breaking); enforce MAX_ANIMATION_FRAMES. 1.0.0: Splash format with metadata and validation.</CLOG>

use serde::{Deserialize, Serialize};

use crate::{validate_dimensions, AnimationData, Cell, FormatError, MAX_ANIMATION_FRAMES};

/// Format version constants for compatibility checking.
pub const SPLASH_VERSION: u8 = 1;
pub const SPLASH_MIN_SUPPORTED: u8 = 1;

#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct SplashMeta {
    pub name: String,
    pub created_at: u64,
    pub editor_version: String,
}

#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct Splash {
    pub version: u8,
    pub meta: SplashMeta,
    pub width: u32,
    pub height: u32,
    pub cells: Vec<Cell>,
    pub animation: Option<AnimationData>,
}

impl Splash {
    pub fn validate(&self) -> Result<(), FormatError> {
        let cells = validate_dimensions(self.width, self.height)?;
        if self.cells.len() != cells {
            return Err(FormatError::CellCountMismatch {
                actual: self.cells.len(),
                expected: cells,
                width: self.width,
                height: self.height,
            });
        }
        if let Some(animation) = &self.animation {
            if animation.frames.len() > MAX_ANIMATION_FRAMES {
                return Err(FormatError::FrameCountExceeded {
                    count: animation.frames.len(),
                    max: MAX_ANIMATION_FRAMES,
                });
            }
            for (idx, frame) in animation.frames.iter().enumerate() {
                if frame.cells.len() != cells {
                    return Err(FormatError::FrameCellCountMismatch {
                        frame: idx,
                        actual: frame.cells.len(),
                        expected: cells,
                    });
                }
            }
        }
        Ok(())
    }
}

// <FILE>crates/rocketsplash-formats/src/splash.rs</FILE>
// <VERS>END OF VERSION: 2.0.0</VERS>