//! Decode errors.
//!
//! Encoding cannot fail: every `Value` is representable on the wire. Decoding
//! is fallible because the input is attacker-shaped bytes from a socket.

use std::fmt;

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Error {
    /// Ran off the end of the buffer while reading `what`.
    Truncated {
        what: &'static str,
        need: usize,
        have: usize,
    },
    /// A type byte that is not one of the eleven Heat2 types.
    UnknownType { type_byte: u8, at: usize },
    /// A varint whose continuation bits never terminated within 64 bits.
    VarintOverflow { at: usize },
    /// A Fire2 header whose declared lengths cannot be satisfied.
    ShortFrame { need: usize, have: usize },
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Error::Truncated { what, need, have } => write!(
                f,
                "truncated while reading {what}: need {need} bytes, have {have}"
            ),
            Error::UnknownType { type_byte, at } => {
                write!(f, "unknown TDF type byte 0x{type_byte:02x} at offset {at}")
            }
            Error::VarintOverflow { at } => {
                write!(f, "varint at offset {at} exceeds 64 bits")
            }
            Error::ShortFrame { need, have } => {
                write!(f, "short Fire2 frame: need {need} bytes, have {have}")
            }
        }
    }
}

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

pub type Result<T> = std::result::Result<T, Error>;
