1use core::fmt;
2use std::error::Error;
3
4#[derive(Debug, Clone, Copy, PartialEq)]
6pub enum ProbabilityError {
7 NonFiniteProbability(f64),
9 ProbabilityOutOfRange(f64),
11 ZeroTotal,
13 PartExceedsTotal {
15 part: u64,
17 total: u64,
19 },
20}
21
22impl ProbabilityError {
23 #[allow(clippy::manual_range_contains)]
24 pub(crate) const fn validate_probability(value: f64) -> Result<f64, Self> {
25 if !value.is_finite() {
26 return Err(Self::NonFiniteProbability(value));
27 }
28
29 if value < 0.0 || value > 1.0 {
30 return Err(Self::ProbabilityOutOfRange(value));
31 }
32
33 Ok(value)
34 }
35
36 pub(crate) const fn validate_fraction(part: u64, total: u64) -> Result<(), Self> {
37 if total == 0 {
38 return Err(Self::ZeroTotal);
39 }
40
41 if part > total {
42 return Err(Self::PartExceedsTotal { part, total });
43 }
44
45 Ok(())
46 }
47}
48
49impl fmt::Display for ProbabilityError {
50 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
51 match self {
52 Self::NonFiniteProbability(value) => {
53 write!(formatter, "probability must be finite, got {value}")
54 },
55 Self::ProbabilityOutOfRange(value) => {
56 write!(formatter, "probability must be in [0, 1], got {value}")
57 },
58 Self::ZeroTotal => write!(formatter, "total count must be greater than zero"),
59 Self::PartExceedsTotal { part, total } => {
60 write!(
61 formatter,
62 "part must be less than or equal to total, got part={part}, total={total}"
63 )
64 },
65 }
66 }
67}
68
69impl Error for ProbabilityError {}