#![cfg_attr(coverage_nightly, feature(coverage_attribute))]
#![warn(missing_docs)]
use clap::parser::MatchesError;
use const_format::formatcp;
use dumping::REQUIRED_PARAM_DESCRIPTION_PREFIX;
use serde::{Deserialize, Serialize};
use serde_json::Value;
use strum::Display;
use validator::ValidationError;
use validators::ParsedValidationErrors;
pub const CONFIG_FILE_ARG_NAME: &str = "config_file";
pub const CONFIG_FILE_SHORT_ARG_NAME: char = 'f';
pub const CONFIG_FILE_ARG: &str = formatcp!("--{}", CONFIG_FILE_ARG_NAME);
pub const IS_NONE_MARK: &str = "#is_none";
pub const FIELD_SEPARATOR: &str = ".";
pub type ParamPath = String;
pub type Description = String;
pub mod behavior_mode;
mod command;
#[cfg(test)]
mod config_test;
pub mod converters;
pub mod dumping;
pub mod loading;
pub mod presentation;
pub mod secrets;
#[cfg(any(feature = "testing", test))]
pub mod test_utils;
pub mod validators;
#[derive(Clone, Serialize, Deserialize, Debug, PartialEq)]
pub enum ParamPrivacyInput {
Private,
Public,
}
#[derive(Clone, Serialize, Deserialize, Debug, PartialEq)]
enum ParamPrivacy {
Private,
Public,
TemporaryValue,
}
impl From<ParamPrivacyInput> for ParamPrivacy {
fn from(user_param_privacy: ParamPrivacyInput) -> Self {
match user_param_privacy {
ParamPrivacyInput::Private => ParamPrivacy::Private,
ParamPrivacyInput::Public => ParamPrivacy::Public,
}
}
}
#[derive(Clone, Serialize, Deserialize, Debug, PartialEq)]
#[serde(rename_all = "snake_case")]
pub enum SerializedContent {
#[serde(rename = "value")]
DefaultValue(Value),
PointerTarget(ParamPath),
ParamType(SerializationType),
}
impl SerializedContent {
fn get_serialization_type(&self) -> Option<SerializationType> {
match self {
SerializedContent::DefaultValue(value) => match value {
Value::Number(num) => {
if num.is_f64() {
Some(SerializationType::Float)
} else if num.is_u64() {
Some(SerializationType::PositiveInteger)
} else {
Some(SerializationType::NegativeInteger)
}
}
Value::Bool(_) => Some(SerializationType::Boolean),
Value::String(_) => Some(SerializationType::String),
_ => None,
},
SerializedContent::PointerTarget(_) => None,
SerializedContent::ParamType(ser_type) => Some(*ser_type),
}
}
}
#[derive(Clone, Serialize, Deserialize, Debug, PartialEq)]
pub struct SerializedParam {
pub description: Description,
#[serde(flatten)]
pub content: SerializedContent,
pub(crate) privacy: ParamPrivacy,
}
impl SerializedParam {
pub fn is_required(&self) -> bool {
self.description.starts_with(REQUIRED_PARAM_DESCRIPTION_PREFIX)
}
pub fn is_private(&self) -> bool {
self.privacy == ParamPrivacy::Private
}
}
#[derive(Clone, Copy, Serialize, Deserialize, Debug, PartialEq, Display)]
#[allow(missing_docs)]
pub enum SerializationType {
Boolean,
Float,
NegativeInteger,
PositiveInteger,
String,
}
#[allow(missing_docs)]
#[derive(thiserror::Error, Debug)]
pub enum ConfigError {
#[error("Changing {param_path} from required type {required} to {given} is not allowed.")]
ChangeRequiredParamType { param_path: String, required: SerializationType, given: Value },
#[error(transparent)]
CommandInput(#[from] clap::error::Error),
#[error(transparent)]
CommandMatches(#[from] MatchesError),
#[error("{component_config_mismatch}")]
ComponentConfigMismatch { component_config_mismatch: String },
#[error(transparent)]
ConfigValidationError(#[from] ParsedValidationErrors),
#[error(transparent)]
IOError(#[from] std::io::Error),
#[error(transparent)]
MissingParam(#[from] serde_json::Error),
#[error("{pointing_param} is not found.")]
PointerSourceNotFound { pointing_param: String },
#[error("{target_param} is not found.")]
PointerTargetNotFound { target_param: String },
#[error("Received an unexpected parameter: {param_path}.")]
UnexpectedParam { param_path: String },
#[error(transparent)]
ValidationError(#[from] ValidationError),
}