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 {}