cyclone-runtime-rust 1.0.1

Rust reference runtime for the Cyclone binary wire format: Writer, Reader, DecodeError.
Documentation
//! Decode errors.
//!
//! Every failure mode of [`Reader`](crate::Reader) is one of the variants of
//! [`DecodeError`]. The runtime never panics on malformed input: a byte stream
//! that does not satisfy the Specification produces an `Err`, not an abort.

use core::fmt;

/// A byte stream that does not satisfy the Cyclone Specification.
///
/// The Specification (RFC-0002 §10) names the error conditions but not the way
/// an implementation reports them. This runtime reports them as values.
///
/// | Variant | Condition on the byte stream |
/// |---------|------------------------------|
/// | [`UnexpectedEof`](Self::UnexpectedEof) | fewer bytes remain than the value requires |
/// | [`InvalidBool`](Self::InvalidBool) | a `bool` byte that is neither `0x00` nor `0x01` |
/// | [`InvalidUtf8`](Self::InvalidUtf8) | a `String` byte region that is not valid UTF-8 |
/// | [`LengthOverflow`](Self::LengthOverflow) | a length/count field beyond the configured limit |
///
/// `InvalidEnum` is deliberately absent: the set of valid values of an enum is
/// schema knowledge, so validating it belongs to the generated codec, not to a
/// runtime that knows nothing about schemas.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum DecodeError {
    /// Fewer bytes remain in the buffer than the value being read requires.
    UnexpectedEof {
        /// Number of bytes the read needed.
        needed: usize,
        /// Number of bytes actually left in the buffer.
        remaining: usize,
    },

    /// A `bool` was encoded as a byte other than `0x00` or `0x01`.
    ///
    /// A conforming decoder MUST NOT read this as "non-zero means true"
    /// (RFC-0002 §2.4). The offending byte is carried for diagnostics.
    InvalidBool(u8),

    /// The byte region of a `String` is not valid UTF-8 (RFC-0002 §3).
    InvalidUtf8,

    /// A length or count field exceeded the configured [`Limits`](crate::Limits).
    ///
    /// This is the configurable, non-normative guard of RFC-0002 §12. The
    /// normative check - a length larger than the bytes actually remaining -
    /// surfaces as [`UnexpectedEof`](Self::UnexpectedEof); both are applied,
    /// and both reject before any memory is allocated.
    LengthOverflow {
        /// The length or count read from the byte stream.
        length: usize,
        /// The configured limit it exceeded.
        limit: usize,
    },
}

impl fmt::Display for DecodeError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match *self {
            DecodeError::UnexpectedEof { needed, remaining } => {
                write!(f, "unexpected eof: needed {needed} bytes, {remaining} remaining")
            }
            DecodeError::InvalidBool(byte) => {
                write!(f, "invalid bool: 0x{byte:02X} is neither 0x00 nor 0x01")
            }
            DecodeError::InvalidUtf8 => f.write_str("invalid utf-8 in string"),
            DecodeError::LengthOverflow { length, limit } => {
                write!(f, "length overflow: length {length} exceeds limit {limit}")
            }
        }
    }
}

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