use std::path::{Path, PathBuf};
#[derive(
Clone,
Copy,
Debug,
Eq,
Hash,
PartialEq,
strum_macros::AsRefStr,
strum_macros::EnumString,
strum_macros::FromRepr,
strum_macros::IntoStaticStr,
)]
#[strum(ascii_case_insensitive)]
pub enum ConfigKey {
#[strum(to_string = "ASSUME_CRITICAL_POINT_STABLE", serialize = "AssumeCriticalPointIsStable")]
AssumeCriticalPointIsStable,
#[strum(to_string = "CRITICAL_WITHIN_1UK", serialize = "CriticalWithin1Uk")]
CriticalWithin1Uk,
#[strum(to_string = "DONT_CHECK_PROPERTY_LIMITS", serialize = "DontCheckPropLimits")]
DontCheckPropLimits,
#[strum(to_string = "CRITICAL_SPLINES_ENABLED", serialize = "CriticalSplinesEnabled")]
EnableCriticalSplines,
#[strum(to_string = "ENABLE_SUPERANCILLARIES", serialize = "EnableSuperancillaries")]
EnableSuperancillaries,
#[strum(
to_string = "HENRYS_LAW_TO_GENERATE_VLE_GUESSES",
serialize = "HenrysLawToGenerateVleGuesses"
)]
HenrysLawToGenerateVleGuesses,
#[strum(to_string = "NORMALIZE_GAS_CONSTANTS", serialize = "NormalizeGasConstants")]
NormalizeGasConstants,
#[strum(to_string = "OVERWRITE_BINARY_INTERACTION", serialize = "OverwriteBinaryInteraction")]
OverwriteBinaryInteraction,
#[strum(to_string = "OVERWRITE_DEPARTURE_FUNCTION", serialize = "OverwriteDepartureFn")]
OverwriteDepartureFn,
#[strum(to_string = "OVERWRITE_FLUIDS", serialize = "OverwriteSubstances")]
OverwriteSubstances,
#[strum(
to_string = "PHASE_ENVELOPE_STARTING_PRESSURE_PA",
serialize = "PhaseEnvelopeStartPressurePa"
)]
PhaseEnvelopeStartPressurePa,
#[strum(to_string = "R_U_CODATA", serialize = "RUCodata")]
RUCodata,
#[strum(to_string = "SPINODAL_MINIMUM_DELTA", serialize = "SpinodalMinDelta")]
SpinodalMinDelta,
#[strum(to_string = "USE_GUESSES_IN_PROPSSI", serialize = "UseGuessesInPropsSi")]
UseGuessesInPropsSi,
#[strum(to_string = "ALTERNATIVE_REFPROP_PATH", serialize = "AltRefpropPath")]
AltRefpropPath,
#[strum(to_string = "ALTERNATIVE_REFPROP_LIBRARY_PATH", serialize = "AltRefpropLibPath")]
AltRefpropLibPath,
#[strum(to_string = "ALTERNATIVE_REFPROP_HMX_BNC_PATH", serialize = "AltRefpropHmxBncPath")]
AltRefpropHmxBncPath,
#[strum(
to_string = "REFPROP_DONT_ESTIMATE_INTERACTION_PARAMETERS",
serialize = "RefpropDontEstimateInteractionParams"
)]
RefpropDontEstimateInteractionParams,
#[strum(
to_string = "REFPROP_IGNORE_ERROR_ESTIMATED_INTERACTION_PARAMETERS",
serialize = "RefpropIgnoreErrorEstimatedInteractionParams"
)]
RefpropIgnoreErrorEstimatedInteractionParams,
#[strum(to_string = "REFPROP_USE_GERG", serialize = "RefpropUseGerg")]
RefpropUseGerg,
#[strum(to_string = "REFPROP_USE_PENGROBINSON", serialize = "RefpropUsePengRobinson")]
RefpropUsePengRobinson,
#[strum(to_string = "ALTERNATIVE_TABLES_DIRECTORY", serialize = "AltTablesPath")]
AltTablesPath,
#[strum(to_string = "FLOAT_PUNCTUATION", serialize = "FloatPunctuation")]
FloatPunctuation,
#[strum(to_string = "LIST_STRING_DELIMITER", serialize = "ListPunctuation")]
ListPunctuation,
#[strum(to_string = "MAXIMUM_TABLE_DIRECTORY_SIZE_IN_GB", serialize = "MaxTableDirSizeInGb")]
MaxTableDirSizeInGb,
#[strum(to_string = "SAVE_RAW_TABLES", serialize = "SaveRawTables")]
SaveRawTables,
#[strum(to_string = "VTPR_ALWAYS_RELOAD_LIBRARY", serialize = "VtPrAlwaysReloadLib")]
VtPrAlwaysReloadLib,
#[strum(to_string = "VTPR_UNIFAC_PATH", serialize = "VtPrUnifacPath")]
VtPrUnifacPath,
}
#[derive(Clone, Debug, PartialEq)]
pub enum ConfigValue<'a> {
Bool(bool),
Float(f64),
Char(char),
OptionPath(Option<&'a Path>),
}
impl From<bool> for ConfigValue<'_> {
fn from(value: bool) -> Self {
Self::Bool(value)
}
}
impl From<&bool> for ConfigValue<'_> {
fn from(value: &bool) -> Self {
Self::Bool(*value)
}
}
impl From<f64> for ConfigValue<'_> {
fn from(value: f64) -> Self {
Self::Float(value)
}
}
impl From<&f64> for ConfigValue<'_> {
fn from(value: &f64) -> Self {
Self::Float(*value)
}
}
impl From<char> for ConfigValue<'_> {
fn from(value: char) -> Self {
Self::Char(value)
}
}
impl From<&char> for ConfigValue<'_> {
fn from(value: &char) -> Self {
Self::Char(*value)
}
}
impl<'a> From<Option<&'a Path>> for ConfigValue<'a> {
fn from(value: Option<&'a Path>) -> Self {
Self::OptionPath(value)
}
}
impl<'a> From<Option<&'a PathBuf>> for ConfigValue<'a> {
fn from(value: Option<&'a PathBuf>) -> Self {
Self::from(value.map(PathBuf::as_path))
}
}
impl<'a> From<&'a Option<PathBuf>> for ConfigValue<'a> {
fn from(value: &'a Option<PathBuf>) -> Self {
Self::from(value.as_ref())
}
}
impl<'a> From<&'a Path> for ConfigValue<'a> {
fn from(value: &'a Path) -> Self {
Self::from(Some(value))
}
}
impl<'a> From<&'a PathBuf> for ConfigValue<'a> {
fn from(value: &'a PathBuf) -> Self {
Self::from(Some(value.as_path()))
}
}
#[cfg(test)]
mod tests {
use rstest::*;
use super::*;
mod key {
use std::str::FromStr;
use super::{ConfigKey::*, *};
#[rstest]
#[case(AssumeCriticalPointIsStable, "ASSUME_CRITICAL_POINT_STABLE")]
#[case(CriticalWithin1Uk, "CRITICAL_WITHIN_1UK")]
#[case(DontCheckPropLimits, "DONT_CHECK_PROPERTY_LIMITS")]
#[case(EnableCriticalSplines, "CRITICAL_SPLINES_ENABLED")]
#[case(EnableSuperancillaries, "ENABLE_SUPERANCILLARIES")]
#[case(HenrysLawToGenerateVleGuesses, "HENRYS_LAW_TO_GENERATE_VLE_GUESSES")]
#[case(NormalizeGasConstants, "NORMALIZE_GAS_CONSTANTS")]
#[case(OverwriteBinaryInteraction, "OVERWRITE_BINARY_INTERACTION")]
#[case(OverwriteDepartureFn, "OVERWRITE_DEPARTURE_FUNCTION")]
#[case(OverwriteSubstances, "OVERWRITE_FLUIDS")]
#[case(PhaseEnvelopeStartPressurePa, "PHASE_ENVELOPE_STARTING_PRESSURE_PA")]
#[case(RUCodata, "R_U_CODATA")]
#[case(SpinodalMinDelta, "SPINODAL_MINIMUM_DELTA")]
#[case(UseGuessesInPropsSi, "USE_GUESSES_IN_PROPSSI")]
#[case(AltRefpropPath, "ALTERNATIVE_REFPROP_PATH")]
#[case(AltRefpropLibPath, "ALTERNATIVE_REFPROP_LIBRARY_PATH")]
#[case(AltRefpropHmxBncPath, "ALTERNATIVE_REFPROP_HMX_BNC_PATH")]
#[case(
RefpropDontEstimateInteractionParams,
"REFPROP_DONT_ESTIMATE_INTERACTION_PARAMETERS"
)]
#[case(
RefpropIgnoreErrorEstimatedInteractionParams,
"REFPROP_IGNORE_ERROR_ESTIMATED_INTERACTION_PARAMETERS"
)]
#[case(RefpropUseGerg, "REFPROP_USE_GERG")]
#[case(RefpropUsePengRobinson, "REFPROP_USE_PENGROBINSON")]
#[case(AltTablesPath, "ALTERNATIVE_TABLES_DIRECTORY")]
#[case(FloatPunctuation, "FLOAT_PUNCTUATION")]
#[case(ListPunctuation, "LIST_STRING_DELIMITER")]
#[case(MaxTableDirSizeInGb, "MAXIMUM_TABLE_DIRECTORY_SIZE_IN_GB")]
#[case(SaveRawTables, "SAVE_RAW_TABLES")]
#[case(VtPrAlwaysReloadLib, "VTPR_ALWAYS_RELOAD_LIBRARY")]
#[case(VtPrUnifacPath, "VTPR_UNIFAC_PATH")]
fn as_str(#[case] sut: ConfigKey, #[case] expected: &str) {
let str = sut.as_ref();
let static_str: &'static str = sut.into();
assert_eq!(str, expected);
assert_eq!(static_str, expected);
}
#[rstest]
#[case(
vec!["ASSUME_CRITICAL_POINT_STABLE", "AssumeCriticalPointIsStable"],
AssumeCriticalPointIsStable
)]
#[case(vec!["CRITICAL_WITHIN_1UK", "CriticalWithin1Uk"], CriticalWithin1Uk)]
#[case(vec!["DONT_CHECK_PROPERTY_LIMITS", "DontCheckPropLimits"], DontCheckPropLimits)]
#[case(vec!["CRITICAL_SPLINES_ENABLED", "CriticalSplinesEnabled"], EnableCriticalSplines)]
#[case(vec!["ENABLE_SUPERANCILLARIES", "EnableSuperancillaries"], EnableSuperancillaries)]
#[case(
vec!["HENRYS_LAW_TO_GENERATE_VLE_GUESSES", "HenrysLawToGenerateVleGuesses"],
HenrysLawToGenerateVleGuesses
)]
#[case(vec!["NORMALIZE_GAS_CONSTANTS", "NormalizeGasConstants"], NormalizeGasConstants)]
#[case(
vec!["OVERWRITE_BINARY_INTERACTION", "OverwriteBinaryInteraction"],
OverwriteBinaryInteraction
)]
#[case(vec!["OVERWRITE_DEPARTURE_FUNCTION", "OverwriteDepartureFn"], OverwriteDepartureFn)]
#[case(vec!["OVERWRITE_FLUIDS", "OverwriteSubstances"], OverwriteSubstances)]
#[case(
vec!["PHASE_ENVELOPE_STARTING_PRESSURE_PA", "PhaseEnvelopeStartPressurePa"],
PhaseEnvelopeStartPressurePa
)]
#[case(vec!["R_U_CODATA", "RUCodata"], RUCodata)]
#[case(vec!["SPINODAL_MINIMUM_DELTA", "SpinodalMinDelta"], SpinodalMinDelta)]
#[case(vec!["USE_GUESSES_IN_PROPSSI", "UseGuessesInPropsSi"], UseGuessesInPropsSi)]
#[case(vec!["ALTERNATIVE_REFPROP_PATH", "AltRefpropPath"], AltRefpropPath)]
#[case(vec!["ALTERNATIVE_REFPROP_LIBRARY_PATH", "AltRefpropLibPath"], AltRefpropLibPath)]
#[case(vec!["ALTERNATIVE_REFPROP_HMX_BNC_PATH", "AltRefpropHmxBncPath"], AltRefpropHmxBncPath)]
#[case(
vec![
"REFPROP_DONT_ESTIMATE_INTERACTION_PARAMETERS",
"RefpropDontEstimateInteractionParams"
],
RefpropDontEstimateInteractionParams
)]
#[case(
vec![
"REFPROP_IGNORE_ERROR_ESTIMATED_INTERACTION_PARAMETERS",
"RefpropIgnoreErrorEstimatedInteractionParams"
],
RefpropIgnoreErrorEstimatedInteractionParams
)]
#[case(vec!["REFPROP_USE_GERG", "RefpropUseGerg"], RefpropUseGerg)]
#[case(vec!["REFPROP_USE_PENGROBINSON", "RefpropUsePengRobinson"], RefpropUsePengRobinson)]
#[case(vec!["ALTERNATIVE_TABLES_DIRECTORY", "AltTablesPath"], AltTablesPath)]
#[case(vec!["FLOAT_PUNCTUATION", "FloatPunctuation"], FloatPunctuation)]
#[case(vec!["LIST_STRING_DELIMITER", "ListPunctuation"], ListPunctuation)]
#[case(
vec!["MAXIMUM_TABLE_DIRECTORY_SIZE_IN_GB", "MaxTableDirSizeInGb"],
MaxTableDirSizeInGb
)]
#[case(vec!["SAVE_RAW_TABLES", "SaveRawTables"], SaveRawTables)]
#[case(vec!["VTPR_ALWAYS_RELOAD_LIBRARY", "VtPrAlwaysReloadLib"], VtPrAlwaysReloadLib)]
#[case(vec!["VTPR_UNIFAC_PATH", "VtPrUnifacPath"], VtPrUnifacPath)]
fn from_valid_str<'a>(#[case] valid: Vec<&'a str>, #[case] expected: ConfigKey) {
for s in valid {
let res1 = ConfigKey::from_str(s).unwrap();
let res2 = ConfigKey::try_from(s).unwrap();
assert_eq!(res1, expected);
assert_eq!(res2, expected);
}
}
#[rstest]
#[case("")]
#[case("Hello, World!")]
fn from_invalid_str(#[case] invalid: &str) {
let res1 = ConfigKey::from_str(invalid);
let res2 = ConfigKey::try_from(invalid);
assert!(res1.is_err());
assert!(res2.is_err());
}
}
mod value {
use super::*;
#[test]
fn from_bool() {
let value = true;
let res = ConfigValue::from(value);
assert_eq!(res, ConfigValue::Bool(value));
}
#[test]
fn from_bool_ref() {
let value = true;
let res = ConfigValue::from(&value);
assert_eq!(res, ConfigValue::Bool(value));
}
#[test]
fn from_float() {
let value = 42.0;
let res = ConfigValue::from(value);
assert_eq!(res, ConfigValue::Float(value));
}
#[test]
fn from_float_ref() {
let value = 42.0;
let res = ConfigValue::from(&value);
assert_eq!(res, ConfigValue::Float(value));
}
#[test]
fn from_char() {
let value = '.';
let res = ConfigValue::from(value);
assert_eq!(res, ConfigValue::Char(value));
}
#[test]
fn from_char_ref() {
let value = '.';
let res = ConfigValue::from(&value);
assert_eq!(res, ConfigValue::Char(value));
}
#[test]
fn from_path() {
let value = Path::new("foo/bar");
let res = ConfigValue::from(value);
assert_eq!(res, ConfigValue::OptionPath(Some(value)));
}
#[test]
fn from_path_buf_ref() {
let value = PathBuf::from("foo/bar");
let res = ConfigValue::from(&value);
assert_eq!(res, ConfigValue::OptionPath(Some(value.as_path())));
}
#[rstest]
#[case(None)]
#[case(Some(Path::new("foo/bar")))]
fn from_option_path(#[case] value: Option<&Path>) {
let res = ConfigValue::from(value);
assert_eq!(res, ConfigValue::OptionPath(value));
}
#[rstest]
#[case(None)]
#[case(Some(PathBuf::from("foo/bar")))]
fn from_option_path_buf_ref(#[case] value: Option<PathBuf>) {
let value = value.as_ref();
let res = ConfigValue::from(value);
assert_eq!(res, ConfigValue::OptionPath(value.map(PathBuf::as_path)));
}
#[rstest]
#[case(None)]
#[case(Some(PathBuf::from("foo/bar")))]
fn from_ref_to_option_path_buf(#[case] value: Option<PathBuf>) {
let res = ConfigValue::from(&value);
assert_eq!(res, ConfigValue::OptionPath(value.as_deref()));
}
}
}