Skip to main content

nexus_decimal/
error.rs

1//! Error types for decimal operations.
2//!
3//! Each error type is scoped to the operations that can produce it.
4//! `checked_*` methods return `Option` (std convention).
5//! `try_*` and fallible constructors return `Result` with the
6//! narrowest error type for that operation.
7//!
8//! ## Error shape convention
9//!
10//! Error shapes in this crate match the number of distinct runtime states:
11//!
12//! - **Single-state errors are unit structs** (e.g., [`OverflowError`]).
13//!   Match arms are `Err(OverflowError)`, no variant pattern needed.
14//! - **Multi-state errors are enums** (e.g., [`DivError`], [`ParseError`]).
15//!   Each variant represents an actually-distinct runtime outcome.
16//!
17//! When adding a new error type, pick the shape that matches its actual
18//! runtime states. Don't make a unit struct into an enum "in case we add
19//! variants later" — bump the type when that case actually arrives.
20
21use core::fmt;
22
23/// Arithmetic overflow (add, sub, mul, neg).
24#[derive(Debug, Clone, Copy, PartialEq, Eq)]
25pub struct OverflowError;
26
27impl fmt::Display for OverflowError {
28    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
29        f.write_str("decimal overflow")
30    }
31}
32
33/// Division failure.
34#[derive(Debug, Clone, Copy, PartialEq, Eq)]
35pub enum DivError {
36    /// Result exceeds representable range.
37    Overflow,
38    /// Divisor is zero.
39    DivisionByZero,
40}
41
42impl fmt::Display for DivError {
43    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
44        match self {
45            Self::Overflow => f.write_str("decimal division overflow"),
46            Self::DivisionByZero => f.write_str("division by zero"),
47        }
48    }
49}
50
51/// String parsing failure.
52#[derive(Debug, Clone, Copy, PartialEq, Eq)]
53pub enum ParseError {
54    /// Input is not a valid decimal string.
55    InvalidFormat,
56    /// Parsed value exceeds representable range.
57    Overflow,
58    /// Input has more decimal places than the type supports.
59    PrecisionLoss,
60}
61
62impl fmt::Display for ParseError {
63    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
64        match self {
65            Self::InvalidFormat => f.write_str("invalid decimal format"),
66            Self::Overflow => f.write_str("decimal parse overflow"),
67            Self::PrecisionLoss => f.write_str("precision loss in decimal parse"),
68        }
69    }
70}
71
72/// Type or float conversion failure.
73#[derive(Debug, Clone, Copy, PartialEq, Eq)]
74pub enum ConvertError {
75    /// Value exceeds target type's representable range.
76    Overflow,
77    /// Conversion would lose precision.
78    PrecisionLoss,
79}
80
81impl fmt::Display for ConvertError {
82    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
83        match self {
84            Self::Overflow => f.write_str("decimal conversion overflow"),
85            Self::PrecisionLoss => f.write_str("precision loss in decimal conversion"),
86        }
87    }
88}
89
90#[cfg(feature = "std")]
91impl std::error::Error for OverflowError {}
92
93#[cfg(feature = "std")]
94impl std::error::Error for DivError {}
95
96#[cfg(feature = "std")]
97impl std::error::Error for ParseError {}
98
99#[cfg(feature = "std")]
100impl std::error::Error for ConvertError {}