Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

D076 — Rust Types (Key Interfaces)

Sub-page of D076 — Standalone MIT/Apache-Licensed Crate Extraction Strategy.

These are the public-facing type signatures that define extraction boundaries. IC wraps or extends these types; it never exposes them directly to players.

#![allow(unused)]
fn main() {
// cnc-formats — clean-room C&C binary format parsing and encoding
pub struct MixArchive { /* ... */ }
pub struct ShpFile { /* ... */ }
pub struct PalFile { /* ... */ }
pub struct TmpFile { /* ... */ }
pub struct AudFile { /* ... */ }
pub struct VqaFile { /* ... */ }

// All format types use a slice-based parsing API:
//   MixArchive::parse(data: &[u8]) -> Result<Self, FormatError>
//   ShpFile::parse(data: &[u8]) -> Result<Self, FormatError>
// Streaming (Read + Seek) is a planned future option — not yet implemented.

// cnc-formats — clean-room encoders (no EA-derived code)
pub mod lcw {
    pub fn compress(input: &[u8]) -> Vec<u8>;
    pub fn decompress(input: &[u8], output: &mut [u8]) -> Result<usize, LcwError>;
}
pub mod shp {
    pub fn encode_frames(frames: &[ShpFrame], palette: &PalFile) -> Result<Vec<u8>, ShpError>;
}
pub mod aud {
    pub fn encode_adpcm(samples: &[i16], sample_rate: u32) -> Result<Vec<u8>, AudError>;
    pub fn build_aud(samples: &[i16], sample_rate: u32, stereo: bool) -> Result<Vec<u8>, AudError>;
}
pub mod pal {
    impl PalFile {
        pub fn encode(&self) -> [u8; 768];
    }
}

// cnc-formats — VQA decode/encode (clean-room VQ codebook via median-cut quantization)
pub mod vqa {
    pub mod decode {
        pub struct VqaFrame { pub width: u16, pub height: u16, pub palette: [PalColor; 256], pub pixels: Vec<u8> }
        pub struct VqaAudio { pub sample_rate: u16, pub channels: u8, pub samples: Vec<i16> }
        // Methods on VqaFile:
        impl VqaFile {
            pub fn decode_frames(&self) -> Result<Vec<VqaFrame>, Error>;
            pub fn extract_audio(&self) -> Option<VqaAudio>;
        }
    }
    pub mod encode {
        pub struct VqaEncodeParams { pub width: u16, pub height: u16, pub fps: u16, pub num_colors: u16, pub block_width: u8, pub block_height: u8 }
        pub struct VqaAudioInput { pub sample_rate: u16, pub channels: u8, pub samples: Vec<i16> }
        pub fn encode_vqa(frames: &[VqaFrame], audio: Option<&VqaAudioInput>, params: &VqaEncodeParams) -> Result<Vec<u8>, Error>;
    }
}

// cnc-formats — MEG/PGM archive parsing (Phase 2, behind `meg` feature flag)
#[cfg(feature = "meg")]
pub struct MegArchive {
    pub entries: Vec<MegEntry>,
}
#[cfg(feature = "meg")]
pub struct MegEntry {
    pub name: String,
    pub offset: u64,
    pub size: u64,
}

// cnc-formats CLI — extensible format conversion via --format/--to flags
/// Available conversion formats. Per-variant `#[cfg]` ensures the binary
/// only includes parsers for enabled features.
#[derive(Clone, Copy, Debug, clap::ValueEnum)]
pub enum ConvertFormat {
    /// Standard YAML (always available)
    Yaml,
    /// OpenRA MiniYAML (requires `miniyaml` feature)
    #[cfg(feature = "miniyaml")]
    Miniyaml,
    /// Classic C&C .ini rules (always available)
    Ini,
    /// IST sprite text (requires `ist` feature)
    #[cfg(feature = "ist")]
    Ist,
    // Binary formats below require `convert` feature
    /// SHP sprite sheet (requires `convert` feature)
    #[cfg(feature = "convert")]
    Shp,
    /// PNG image (requires `convert` feature)
    #[cfg(feature = "convert")]
    Png,
    /// GIF image/animation (requires `convert` feature)
    #[cfg(feature = "convert")]
    Gif,
    /// PAL color palette (requires `convert` feature)
    #[cfg(feature = "convert")]
    Pal,
    /// TMP terrain tiles (requires `convert` feature)
    #[cfg(feature = "convert")]
    Tmp,
    /// WSA animation (requires `convert` feature)
    #[cfg(feature = "convert")]
    Wsa,
    /// AUD Westwood audio (requires `convert` feature)
    #[cfg(feature = "convert")]
    Aud,
    /// WAV audio (requires `convert` feature)
    #[cfg(feature = "convert")]
    Wav,
    /// VQA video (requires `convert` feature)
    #[cfg(feature = "convert")]
    Vqa,
    /// AVI video — interchange format for VQA conversion (requires `convert` feature)
    #[cfg(feature = "convert")]
    Avi,
    /// FNT bitmap font (requires `convert` feature)
    #[cfg(feature = "convert")]
    Fnt,
    /// MIDI file (requires `midi` feature)
    #[cfg(feature = "midi")]
    Mid,
    /// AdLib OPL2 register data (requires `adl` feature)
    #[cfg(feature = "adl")]
    Adl,
    /// XMIDI / Miles Sound System (requires `xmi` feature)
    #[cfg(feature = "xmi")]
    Xmi,
}

/// `cnc-formats convert` subcommand arguments.
#[derive(clap::Args)]
pub struct ConvertArgs {
    /// Source format override (auto-detected from file extension when
    /// unambiguous; required when reading from stdin). Shared with
    /// `validate` and `inspect` — always means "source format override."
    #[arg(long)]
    pub format: Option<ConvertFormat>,
    /// Target format (always required).
    #[arg(long)]
    pub to: ConvertFormat,
    /// Input file path (omit or use `-` for stdin).
    pub input: Option<PathBuf>,
    /// Output file path (omit for stdout).
    #[arg(short, long)]
    pub output: Option<PathBuf>,
    /// Palette file path (required for SHP/TMP conversions that need color data).
    #[arg(long)]
    pub palette: Option<PathBuf>,
    /// SoundFont file path (required for MIDI→WAV/AUD conversions).
    #[cfg(feature = "midi")]
    #[arg(long)]
    pub soundfont: Option<PathBuf>,
}

/// Dispatch: match on `(format, to)` pairs. Unsupported pairs print
/// available conversions and exit with a non-zero status code.
fn convert(args: &ConvertArgs) -> Result<Vec<u8>> {
    let format = args.format.unwrap_or_else(|| detect_format(&args.input));
    let input = &args.input;       // shorthand — all converters take input path
    let palette = &args.palette;   // Option<PathBuf> — required for SHP/TMP
    #[cfg(feature = "midi")]
    let soundfont = &args.soundfont; // Option<PathBuf> — required for MIDI→WAV/AUD

    match (format, args.to) {
        #[cfg(feature = "miniyaml")]
        (ConvertFormat::Miniyaml, ConvertFormat::Yaml) => miniyaml_to_yaml(input),
        #[cfg(feature = "convert")]
        (ConvertFormat::Shp, ConvertFormat::Png) => shp_to_png(input, palette),
        #[cfg(feature = "convert")]
        (ConvertFormat::Png, ConvertFormat::Shp) => png_to_shp(input, palette),
        #[cfg(feature = "convert")]
        (ConvertFormat::Aud, ConvertFormat::Wav) => aud_to_wav(input),
        #[cfg(feature = "convert")]
        (ConvertFormat::Wav, ConvertFormat::Aud) => wav_to_aud(input),
        #[cfg(feature = "convert")]
        (ConvertFormat::Vqa, ConvertFormat::Avi) => vqa_to_avi(input),
        #[cfg(feature = "convert")]
        (ConvertFormat::Avi, ConvertFormat::Vqa) => avi_to_vqa(input),
        #[cfg(feature = "midi")]
        (ConvertFormat::Mid, ConvertFormat::Wav) => mid_to_wav(input, soundfont),
        #[cfg(all(feature = "midi", feature = "convert"))]
        (ConvertFormat::Mid, ConvertFormat::Aud) => mid_to_aud(input, soundfont),
        #[cfg(feature = "xmi")]
        (ConvertFormat::Xmi, ConvertFormat::Mid) => xmi_to_mid(input),
        #[cfg(feature = "xmi")]
        (ConvertFormat::Xmi, ConvertFormat::Wav) => xmi_to_wav(input, soundfont),
        #[cfg(all(feature = "xmi", feature = "convert"))]
        (ConvertFormat::Xmi, ConvertFormat::Aud) => xmi_to_aud(input, soundfont),
        // ... additional pairs for GIF, WSA, TMP, PAL, FNT
        (f, t) => Err(UnsupportedConversion { from: f, to: t }),
    }
}

// cnc-formats MIDI types (behind `midi` feature flag)
// Dependencies: midly (Unlicense), nodi (MIT), rustysynth (MIT)
#[cfg(feature = "midi")]
pub mod mid {
    /// Parsed MIDI file — wraps midly::Smf with additional metadata.
    pub struct MidFile { /* tracks, tempo, duration, channel info */ }

    /// Parse a MIDI file from bytes.
    pub fn parse(data: &[u8]) -> Result<MidFile>;

    /// Write a MIDI file to bytes.
    pub fn write(mid: &MidFile) -> Result<Vec<u8>>;

    /// Render MIDI to PCM audio via SoundFont synthesis (rustysynth).
    /// Returns interleaved f32 stereo samples at the given sample rate.
    pub fn render_to_pcm(mid: &MidFile, soundfont: &SoundFont, sample_rate: u32) -> Result<Vec<f32>>;

    /// Render MIDI to WAV file bytes via SoundFont synthesis.
    pub fn render_to_wav(mid: &MidFile, soundfont: &SoundFont, sample_rate: u32) -> Result<Vec<u8>>;
}

// cnc-formats ADL types (behind `adl` feature flag)
// No external dependencies — pure Rust parser
#[cfg(feature = "adl")]
pub mod adl {
    /// Parsed AdLib OPL2 register data file (Dune II .adl format).
    /// Contains sequential register write commands with timing information.
    pub struct AdlFile {
        pub register_writes: Vec<AdlRegisterWrite>,
        pub estimated_duration_ms: u32,
    }

    /// A single OPL2 register write with timing offset.
    pub struct AdlRegisterWrite {
        pub register: u8,
        pub value: u8,
        pub delay_ticks: u16,
    }

    /// Parse an .adl file from bytes.
    pub fn parse(data: &[u8]) -> Result<AdlFile>;
}

// cnc-formats XMI types (behind `xmi` feature flag, implies `midi`)
// Depends on midly (via `midi` feature) for MID output
#[cfg(feature = "xmi")]
pub mod xmi {
    /// Parsed XMIDI file — IFF FORM:XMID container with Miles Sound System extensions.
    pub struct XmiFile {
        pub sequences: Vec<XmiSequence>,
    }

    /// A single XMIDI sequence (multi-sequence files contain several).
    pub struct XmiSequence {
        pub events: Vec<XmiEvent>,
        pub timing_mode: XmiTimingMode,
    }

    /// XMIDI timing modes — IFTHEN (absolute) vs. standard delta-time.
    pub enum XmiTimingMode { Ifthen, DeltaTime }

    /// Parse an .xmi file from bytes.
    pub fn parse(data: &[u8]) -> Result<XmiFile>;

    /// Convert XMIDI to standard MIDI file.
    /// Strips IFF wrapper, converts IFTHEN timing to delta-time,
    /// merges multi-sequence files into a single SMF Type 1.
    pub fn to_mid(xmi: &XmiFile) -> Result<mid::MidFile>;
}

// fixed-game-math — deterministic fixed-point arithmetic
pub struct Fixed<const FRAC_BITS: u32>(i64);
pub struct WorldPos { pub x: Fixed<10>, pub y: Fixed<10>, pub z: Fixed<10> }
pub struct WAngle(i32);  // 0..1024 = 0°..360°

impl Fixed<FRAC_BITS> {
    pub const fn from_int(v: i32) -> Self;
    pub fn sin(angle: WAngle) -> Self;  // table lookup
    pub fn cos(angle: WAngle) -> Self;
    pub fn atan2(y: Self, x: Self) -> WAngle;  // CORDIC
    pub fn sqrt(self) -> Self;  // Newton's method
}

// deterministic-rng — seedable, platform-identical PRNG
pub struct GameRng { /* xoshiro256** or similar */ }

impl GameRng {
    pub fn from_seed(seed: u64) -> Self;
    pub fn next_u32(&mut self) -> u32;
    pub fn range(&mut self, min: i32, max: i32) -> i32;
    pub fn weighted_select<T>(&mut self, items: &[(T, u32)]) -> &T;
    pub fn shuffle<T>(&mut self, slice: &mut [T]);
    pub fn damage_spread(&mut self, base: i32, spread_pct: u32) -> i32;
}

// glicko2-rts — rating system with RTS adaptations
pub struct Rating {
    pub mu: f64,
    pub phi: f64,    // rating deviation
    pub sigma: f64,  // volatility
}

pub struct MatchResult {
    pub players: Vec<(PlayerId, Rating)>,
    pub outcome: Outcome,
    pub duration_secs: u32,
    pub faction: Option<FactionId>,
}

pub fn update_ratings(results: &[MatchResult], config: &Glicko2Config) -> Vec<(PlayerId, Rating)>;

// lockstep-relay — game-agnostic relay core
pub struct RelayCore<T: OrderCodec> { /* ... */ }

impl<T: OrderCodec> RelayCore<T> {
    pub fn new(config: RelayConfig) -> Self;
    pub fn tick(&mut self) -> Vec<RelayEvent<T>>;
    pub fn submit_order(&mut self, player: PlayerId, order: T);
    pub fn player_connected(&mut self, player: PlayerId);
    pub fn player_disconnected(&mut self, player: PlayerId);
}

// workshop-core — engine-agnostic mod registry (D050)
pub struct Package { /* ... */ }
pub struct Manifest { /* ... */ }
pub struct Registry { /* ... */ }

pub trait PackageStore {
    fn publish(&self, package: &Package) -> Result<(), StoreError>;
    fn fetch(&self, id: &PackageId, version: &VersionReq) -> Result<Package, StoreError>;
    fn resolve(&self, deps: &[Dependency]) -> Result<Vec<Package>, ResolveError>;
}
}