diff --git a/src/convergence.rs b/src/convergence.rs index 660edd9..c0168cc 100644 --- a/src/convergence.rs +++ b/src/convergence.rs @@ -11,6 +11,14 @@ use smallvec::SmallVec; /// carried by `GameOptions` for a single match scored without a history. The /// defaults are the crate's globals: [`ITERATIONS`](crate::ITERATIONS), /// [`EPSILON`](crate::EPSILON), and undamped EP. +/// +/// Deliberately **not** `#[non_exhaustive]`, unlike [`ConvergenceReport`]. The +/// usual argument for marking an options struct is that `..Default::default()` +/// makes a future field additive — but `Default::default` is not a `const fn`, +/// so marking it would make +/// `const OPTS: ConvergenceOptions = ConvergenceOptions { .. }` impossible from +/// outside the crate, with no workaround. This type is `Copy` and a natural +/// const; that cost is permanent, and adding a field is a one-time major bump. #[derive(Clone, Copy, Debug, PartialEq)] pub struct ConvergenceOptions { /// Hard cap on full forward+backward sweeps. @@ -89,7 +97,12 @@ impl Default for ConvergenceOptions { /// [`InferenceError::NotConverged`](crate::InferenceError::NotConverged) there. /// From [`History::converge_partial`](crate::History::converge_partial) it may /// not be, and `converged` is what says so. +/// Constructed only by `converge` / `converge_partial`, never by a caller, so +/// `#[non_exhaustive]` costs nothing here and lets a future field be additive. +/// The two *options* structs deliberately do not carry it — see the note on +/// [`ConvergenceOptions`]. #[derive(Clone, Debug, PartialEq)] +#[non_exhaustive] pub struct ConvergenceReport { /// Full forward+backward sweeps actually run. `0` for a history with no /// time slices, which is converged trivially.