bnb/error.rs
1//! The crate's error type and result alias.
2//!
3//! Hand-rolled (no `thiserror`) to keep `bnb` dependency-light — protocol crates
4//! depend on `bnb` *instead of* a stack of external helpers, so `bnb` itself
5//! stays lean.
6
7use core::fmt;
8
9/// Errors from checked construction.
10///
11/// Currently the only fallible operation is `UInt::try_new` (and the `TryFrom`
12/// impls built on it). Decoding never fails: the codec is dual-use, so unknown
13/// values are preserved as `Custom`/catch-all rather than rejected, and field
14/// access masks rather than validates.
15///
16/// # Examples
17///
18/// ```
19/// use bnb::{u4, Error};
20///
21/// let err = u4::try_new(20).unwrap_err(); // 20 doesn't fit in 4 bits
22/// assert_eq!(err, Error::ValueTooLarge { value: 20, bits: 4 });
23/// assert_eq!(err.to_string(), "value 20 does not fit in 4 bits");
24/// ```
25#[derive(Clone, Debug, PartialEq, Eq)]
26pub enum Error {
27 /// A value did not fit in the target integer's bit width.
28 ValueTooLarge {
29 /// The offending value.
30 value: u128,
31 /// The maximum number of bits available.
32 bits: u32,
33 },
34}
35
36impl fmt::Display for Error {
37 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
38 match self {
39 Error::ValueTooLarge { value, bits } => {
40 write!(f, "value {value} does not fit in {bits} bits")
41 }
42 }
43 }
44}
45
46impl core::error::Error for Error {}
47
48/// A `Result` specialized to [`Error`].
49pub type Result<T> = core::result::Result<T, Error>;
50
51/// The error returned by the `TryFrom<uN>` impl that `#[derive(BitEnum)]`
52/// generates for a **byte-aligned enum without a `#[catch_all]` variant**: the
53/// value matched no known discriminant.
54///
55/// A catch-all enum is total, so its primitive→enum conversion is an infallible
56/// `From` and never produces this. This mirrors `num_enum`'s
57/// `TryFromPrimitiveError`. Decoding through the codec / `Bits::from_bits` is
58/// unaffected — that path stays permissive (dual-use); this is only for the
59/// caller who opts into a checked conversion.
60///
61/// # Examples
62///
63/// ```
64/// #[derive(bnb::BitEnum, Clone, Copy, Debug, PartialEq, Eq)]
65/// #[bit_enum(u8, closed)]
66/// #[repr(u8)]
67/// enum Direction { Request = 1, Reply = 2 }
68///
69/// let err = Direction::try_from(9u8).unwrap_err(); // no variant for 9
70/// assert_eq!(err.value, 9);
71/// assert_eq!(err.type_name, "Direction");
72/// assert_eq!(err.to_string(), "Direction has no variant for discriminant 9");
73/// ```
74#[derive(Clone, Debug, PartialEq, Eq)]
75pub struct UnknownDiscriminant {
76 /// The unrecognized value.
77 pub value: u128,
78 /// The name of the enum that rejected it.
79 pub type_name: &'static str,
80}
81
82impl fmt::Display for UnknownDiscriminant {
83 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
84 write!(
85 f,
86 "{} has no variant for discriminant {}",
87 self.type_name, self.value
88 )
89 }
90}
91
92impl core::error::Error for UnknownDiscriminant {}