use crate::composition::{MAX_RATIONAL_DENOMINATOR, RATIONAL_TOLERANCE};
use thiserror::Error;
#[derive(Debug, Error, Clone, PartialEq)]
pub enum GugenError {
#[error("range invalid: min ({min}) must be <= max ({max})")]
InvalidRange { min: f64, max: f64 },
#[error("{field} must be finite, got {value}")]
NonFiniteValue { field: &'static str, value: f64 },
#[error("{field} must be non-negative, got {value}")]
NegativeMagnitude { field: &'static str, value: f64 },
#[error("{field} must be > 0, got {value}")]
NonPositiveMagnitude { field: &'static str, value: f64 },
#[error("composition must contain at least one element")]
EmptyComposition,
#[error("'{0}' is not a recognized element symbol")]
InvalidElementSymbol(String),
#[error("amount for element {element} must be finite and > 0, got {amount}")]
NonPositiveAmount { element: String, amount: f64 },
#[error("element {element} was supplied more than once in the same composition")]
DuplicateElement { element: String },
#[error(
"amount {value} for element {element} is not a simple rational number gugen can balance exactly (need a denominator <= {MAX_RATIONAL_DENOMINATOR} within tolerance {RATIONAL_TOLERANCE})"
)]
AmountNotRational { element: String, value: f64 },
#[error("reaction species coefficients must be > 0")]
ZeroCoefficient,
#[error("Score01 must be finite and within [0, 1], got {value}")]
ScoreOutOfRange { value: f64 },
#[error("a reaction needs at least one reactant and one product")]
EmptyReaction,
#[error("exact arithmetic overflowed while balancing a reaction")]
ArithmeticOverflow,
#[error(
"element {element} is not conserved between reactant and product sides (imbalance {imbalance})"
)]
UnbalancedReaction { element: String, imbalance: f64 },
#[error("inconsistent thermodynamic dataset: {0}")]
InconsistentThermodynamicDataset(String),
#[error("precursor catalog failed: {0}")]
Catalog(#[from] ProviderError),
}
pub type Result<T> = std::result::Result<T, GugenError>;
pub(crate) fn require_finite(field: &'static str, value: f64) -> Result<()> {
if value.is_finite() {
Ok(())
} else {
Err(GugenError::NonFiniteValue { field, value })
}
}
#[derive(Debug, Error, Clone, PartialEq)]
pub enum ProviderError {
#[error("provider unavailable: {0}")]
Unavailable(String),
#[error("entry not found for the requested target")]
MissingEntry,
#[error("malformed record: {0}")]
MalformedRecord(String),
}