qubit-text-codec 0.1.0

Buffer-oriented text encoding and decoding utilities for Rust
Documentation
/*******************************************************************************
 *
 *    Copyright (c) 2026 Haixing Hu.
 *
 *    SPDX-License-Identifier: Apache-2.0
 *
 *    Licensed under the Apache License, Version 2.0.
 *
 ******************************************************************************/
use core::fmt;
use std::error::Error;

use crate::{
    Charset,
    CharsetDecodeErrorKind,
};

/// Error reported by a charset decoder.
///
/// The error always carries the charset, error kind, and input unit index at
/// which the failure was detected. Errors that decode a raw numeric value, such
/// as invalid UTF-32 units, carry that value through [`Self::kind`] and
/// [`Self::value`].
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct CharsetDecodeError {
    /// Charset being decoded when this error was detected.
    charset: Charset,
    /// Failure category describing the decoding error.
    kind: CharsetDecodeErrorKind,
    /// Input unit index at which decoding failure occurred.
    index: usize,
}

/// Result type returned by charset decoders.
///
/// # Type Parameters
///
/// - `T`: Successful value produced by a decoding operation.
pub type CharsetDecodeResult<T> = Result<T, CharsetDecodeError>;

impl CharsetDecodeError {
    /// Creates a decoding error.
    ///
    /// # Parameters
    ///
    /// - `charset`: The charset being decoded.
    /// - `kind`: The failure category.
    /// - `index`: The input unit index where the failure was detected.
    ///
    /// # Returns
    ///
    /// Returns a decoding error carrying the supplied context.
    #[inline]
    pub const fn new(charset: Charset, kind: CharsetDecodeErrorKind, index: usize) -> Self {
        Self { charset, kind, index }
    }

    /// Returns the charset being decoded.
    ///
    /// # Returns
    ///
    /// Returns the stored [`Charset`].
    #[inline]
    pub const fn charset(self) -> Charset {
        self.charset
    }

    /// Returns the decoding error kind.
    ///
    /// # Returns
    ///
    /// Returns the stored [`CharsetDecodeErrorKind`].
    #[inline]
    pub const fn kind(self) -> CharsetDecodeErrorKind {
        self.kind
    }

    /// Returns the input unit index associated with this error.
    ///
    /// # Returns
    ///
    /// Returns the index at which the error was detected.
    #[inline]
    pub const fn index(self) -> usize {
        self.index
    }

    /// Returns required input units for this decoding error, if reported.
    ///
    /// # Returns
    ///
    /// Returns `Some(required)` for [`CharsetDecodeErrorKind::IncompleteSequence`],
    /// otherwise `None`.
    #[inline]
    pub const fn required(self) -> Option<usize> {
        self.kind.required()
    }

    /// Returns available input units for this decoding error, if reported.
    ///
    /// # Returns
    ///
    /// Returns `Some(available)` for [`CharsetDecodeErrorKind::IncompleteSequence`],
    /// otherwise `None`.
    #[inline]
    pub const fn available(self) -> Option<usize> {
        self.kind.available()
    }

    /// Returns the raw value associated with this error.
    ///
    /// # Returns
    ///
    /// Returns `Some(value)` when the error kind carries a raw unit or code
    /// point value, or `None` for kinds without an associated value.
    #[inline]
    pub const fn value(self) -> Option<u32> {
        self.kind.value()
    }

    /// Offsets this error by a base unit index.
    ///
    /// # Parameters
    ///
    /// - `base`: The base index to add to the stored index.
    ///
    /// # Returns
    ///
    /// Returns a copy of this error with its index shifted by `base`.
    #[inline]
    pub const fn offset_by(self, base: usize) -> Self {
        Self {
            charset: self.charset,
            kind: self.kind,
            index: self.index + base,
        }
    }
}

impl fmt::Display for CharsetDecodeError {
    /// Formats this decoding error.
    ///
    /// # Parameters
    ///
    /// - `formatter`: The formatter receiving the diagnostic message.
    ///
    /// # Errors
    ///
    /// Returns any formatting error reported by `formatter`.
    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
        if let Some(value) = self.kind.value() {
            write!(
                formatter,
                "{} decoding error at index {} for value 0x{:x}: {}",
                self.charset, self.index, value, self.kind,
            )
        } else {
            write!(
                formatter,
                "{} decoding error at index {}: {}",
                self.charset, self.index, self.kind,
            )
        }
    }
}

impl Error for CharsetDecodeError {}