Skip to main content

chromy_core/
error.rs

1use std::fmt;
2
3/// Why a procedure refused to run, or could not finish.
4///
5/// Refusals are loud on purpose: a sampling procedure that silently mends
6/// its input produces a sample whose inclusion probabilities nobody knows,
7/// and the weights built from them estimate nothing.
8#[derive(Debug, Clone, PartialEq)]
9pub enum Error {
10    /// The input cannot define a valid selection — a negative size, a
11    /// uniform outside `[0, 1)`, mismatched lengths. The message says which.
12    Input(String),
13
14    /// The expected hits summed too far from an integer to be a sample
15    /// size: the drift exceeds the procedure's tolerance of `1e-8`, so the
16    /// caller's expected hits do not add to a whole number of selections.
17    Drift { eps: f64 },
18
19    /// The floating-point drift could not be absorbed: no unit has a
20    /// fractional expected hit large enough to take the correction.
21    NoAbsorber { eps: f64 },
22
23    /// After the corrections, units with positive expected hits were left
24    /// with no probability of selection at all. Their weights would be
25    /// infinite; the selection is refused instead.
26    LostProbability { units: usize },
27
28    /// The procedure's own accounting failed — realised hits that do not
29    /// add to the sample size. This is a bug in the crate, not in the
30    /// input; please report it.
31    Internal(String),
32}
33
34impl fmt::Display for Error {
35    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
36        match self {
37            Error::Input(what) => write!(f, "invalid input: {what}"),
38            Error::Drift { eps } => write!(
39                f,
40                "the expected hits sum {eps:e} away from an integer, beyond the 1e-8 \
41                 tolerance; they do not define a sample size"
42            ),
43            Error::NoAbsorber { eps } => write!(
44                f,
45                "no unit can absorb the floating-point drift of {eps:e}: every \
46                 fractional expected hit is too small"
47            ),
48            Error::LostProbability { units } => write!(
49                f,
50                "{units} unit(s) with positive expected hits were left with no \
51                 probability of selection"
52            ),
53            Error::Internal(what) => write!(f, "internal accounting error: {what}"),
54        }
55    }
56}
57
58impl std::error::Error for Error {}