//! All the errors that may be returned from [`instructions`].

use crate::prelude::*;

#[derive(Debug)]
/// Error type for parsing register numbers.
pub enum RegisterParseError {
    InvalidIndex(u8),
    InvalidName(String),
}

impl std::fmt::Display for RegisterParseError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            Self::InvalidIndex(idx) => write!(f, "invalid index given ({idx})"),
            Self::InvalidName(name) => write!(f, "invalid name given ({name})"),
        }
    }
}

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

/// A list of errors that can be returned when decoding instructions.
#[derive(Debug)]
pub enum InstructionDecodeError {
    /// Some field was incorrect. Returns an error for debugging purposes.
    InvalidArgument(ArgsDecodeError),
    /// Some opcode was invalid. Returns the offending opcode for debugging purposes etc.
    InvalidOpcode(u8),
}

impl From<ArgsDecodeError> for InstructionDecodeError {
    fn from(err: ArgsDecodeError) -> Self {
        Self::InvalidArgument(err)
    }
}

impl std::fmt::Display for InstructionDecodeError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            Self::InvalidOpcode(code) => write!(f, "invalid opcode, got {code:x}")?,
            Self::InvalidArgument(err) => write!(f, "invalid arguments, got an error {err}")?,
        }

        Ok(())
    }
}

impl std::error::Error for InstructionDecodeError {
    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
        match self {
            Self::InvalidArgument(err) => Some(err),
            _ => None,
        }
    }
}
