rocketsplash-formats 0.3.0

Shared data types and serialization formats for Rocketsplash TUI animations
Documentation
// <FILE>crates/rocketsplash-formats/src/fnc_read_font_atlas.rs</FILE>
// <DESC>Hardened decode entry point for serialized font atlases (.rsf)</DESC>
// <VERS>VERSION: 1.0.0</VERS>
// <WCTX>Foundation crates 0.3.0 (RELEASE_PLAN D3 adversarial hardening)</WCTX>
// <CLOG>1.0.0: canonical size-capped, version-checked, validated decode path; consumers must not call rmp_serde on atlas bytes directly.</CLOG>

use crate::col_peek_version::peek_version;
use crate::{
    FontAtlas, FormatError, FONT_ATLAS_MIN_SUPPORTED, FONT_ATLAS_VERSION, MAX_SERIALIZED_BYTES,
};

/// Decode and validate a `FontAtlas` from MessagePack bytes.
///
/// Enforces, in order: the serialized-size cap, the version window (peeked
/// from the header so future-version files fail with `UnsupportedVersion`,
/// not a decode error), and full structural validation (`limits.rs` bounds).
pub fn read_font_atlas(bytes: &[u8]) -> Result<FontAtlas, FormatError> {
    if bytes.len() > MAX_SERIALIZED_BYTES {
        return Err(FormatError::PayloadTooLarge {
            len: bytes.len(),
            max: MAX_SERIALIZED_BYTES,
        });
    }
    let version = peek_version(bytes);
    if let Some(found) = version {
        check_version(found)?;
    }
    let atlas: FontAtlas =
        rmp_serde::from_slice(bytes).map_err(|err| FormatError::Decode(err.to_string()))?;
    check_version(atlas.version)?;
    atlas.validate()?;
    Ok(atlas)
}

fn check_version(found: u8) -> Result<(), FormatError> {
    if !(FONT_ATLAS_MIN_SUPPORTED..=FONT_ATLAS_VERSION).contains(&found) {
        return Err(FormatError::UnsupportedVersion {
            format: "font atlas",
            found,
            min_supported: FONT_ATLAS_MIN_SUPPORTED,
            current: FONT_ATLAS_VERSION,
        });
    }
    Ok(())
}

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