darkomen 0.5.0

Warhammer: Dark Omen library and CLI in Rust
Documentation
use core::fmt;
use std::io::{BufWriter, Write};

use super::*;

#[derive(Debug)]
pub enum EncodeError {
    IoError(std::io::Error),
}

impl std::error::Error for EncodeError {}

impl From<std::io::Error> for EncodeError {
    fn from(err: std::io::Error) -> Self {
        EncodeError::IoError(err)
    }
}

impl std::fmt::Display for EncodeError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> fmt::Result {
        match self {
            EncodeError::IoError(e) => write!(f, "IO error: {e}"),
        }
    }
}

pub struct Encoder<W: Write> {
    writer: BufWriter<W>,
}

impl<W: Write> Encoder<W> {
    pub fn new(writer: W) -> Self {
        Encoder {
            writer: BufWriter::new(writer),
        }
    }

    pub fn encode(&mut self, sequences: &Sequences) -> Result<(), EncodeError> {
        self.writer.write_all(&[sequences.0.len() as u8])?;

        for sequence in &sequences.0 {
            self.write_sequence(sequence)?;
        }
        Ok(())
    }

    fn write_sequence(&mut self, sequence: &Sequence) -> Result<(), EncodeError> {
        self.writer.write_all(&[sequence.commands.len() as u8])?;

        for command in &sequence.commands {
            self.write_command(command)?;
        }

        Ok(())
    }

    fn write_command(&mut self, command: &Command) -> Result<(), EncodeError> {
        let bytes = match command {
            Command::Delay { time } => [0x01, *time, 0x00, 0x00],
            Command::EndSequence => [0x02, 0x00, 0x00, 0x00],
            Command::RotateToKeyframe {
                interpolation,
                time,
                keyframe_index,
            } => [0x03, *interpolation, *time, *keyframe_index],
            Command::Eyes { open } => [0x05, if *open { 0x01 } else { 0x00 }, 0x00, 0x00],
            Command::Mouth { state } => [0x06, *state, 0x00, 0x00],
            Command::Loop => [0x08, 0x00, 0x00, 0x00],
            Command::LoopWithCounter {
                counter_high,
                counter_low,
            } => [0x09, *counter_high, *counter_low, 0x00],
            Command::StartTalking {
                facial_animation_index,
            } => [0x0A, *facial_animation_index, 0x00, 0x00],
            Command::MouthAnimation {
                facial_animation_index,
            } => [0x0B, *facial_animation_index, 0x00, 0x00],
            Command::EndMouthAnimation => [0x0C, 0x00, 0x00, 0x00],
            Command::InitialRotateToKeyframe {
                interpolation,
                time,
                keyframe_index,
            } => [0x13, *interpolation, *time, *keyframe_index],
            Command::Unknown { opcode, data } => [*opcode, data[0], data[1], data[2]],
        };

        self.writer.write_all(&bytes)?;
        Ok(())
    }
}