bitsandbytes 0.1.0

An owned, bit-aware binary codec: fast bit/byte field types and the unified #[bin] macro.
Documentation
//! The crate's error type and result alias.
//!
//! Hand-rolled (no `thiserror`) to keep `bnb` dependency-light — protocol crates
//! depend on `bnb` *instead of* a stack of external helpers, so `bnb` itself
//! stays lean.

use core::fmt;

/// Errors from checked construction.
///
/// Currently the only fallible operation is `UInt::try_new` (and the `TryFrom`
/// impls built on it). Decoding never fails: the codec is dual-use, so unknown
/// values are preserved as `Custom`/catch-all rather than rejected, and field
/// access masks rather than validates.
///
/// # Examples
///
/// ```
/// use bnb::{u4, Error};
///
/// let err = u4::try_new(20).unwrap_err(); // 20 doesn't fit in 4 bits
/// assert_eq!(err, Error::ValueTooLarge { value: 20, bits: 4 });
/// assert_eq!(err.to_string(), "value 20 does not fit in 4 bits");
/// ```
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum Error {
    /// A value did not fit in the target integer's bit width.
    ValueTooLarge {
        /// The offending value.
        value: u128,
        /// The maximum number of bits available.
        bits: u32,
    },
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Error::ValueTooLarge { value, bits } => {
                write!(f, "value {value} does not fit in {bits} bits")
            }
        }
    }
}

impl core::error::Error for Error {}

/// A `Result` specialized to [`Error`].
pub type Result<T> = core::result::Result<T, Error>;

/// The error returned by the `TryFrom<uN>` impl that `#[derive(BitEnum)]`
/// generates for a **byte-aligned enum without a `#[catch_all]` variant**: the
/// value matched no known discriminant.
///
/// A catch-all enum is total, so its primitive→enum conversion is an infallible
/// `From` and never produces this. This mirrors `num_enum`'s
/// `TryFromPrimitiveError`. Decoding through the codec / `Bits::from_bits` is
/// unaffected — that path stays permissive (dual-use); this is only for the
/// caller who opts into a checked conversion.
///
/// # Examples
///
/// ```
/// #[derive(bnb::BitEnum, Clone, Copy, Debug, PartialEq, Eq)]
/// #[bit_enum(u8, closed)]
/// #[repr(u8)]
/// enum Direction { Request = 1, Reply = 2 }
///
/// let err = Direction::try_from(9u8).unwrap_err(); // no variant for 9
/// assert_eq!(err.value, 9);
/// assert_eq!(err.type_name, "Direction");
/// assert_eq!(err.to_string(), "Direction has no variant for discriminant 9");
/// ```
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct UnknownDiscriminant {
    /// The unrecognized value.
    pub value: u128,
    /// The name of the enum that rejected it.
    pub type_name: &'static str,
}

impl fmt::Display for UnknownDiscriminant {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(
            f,
            "{} has no variant for discriminant {}",
            self.type_name, self.value
        )
    }
}

impl core::error::Error for UnknownDiscriminant {}