use qubit_value::MultiValues;
use crate::config_reader::ConfigReader;
use crate::options::ConfigReadOptions;
use crate::{ConfigResult, Property, utils};
use super::config_parse_context::ConfigParseContext;
use super::from_config::FromConfig;
pub(crate) fn first_scalar_string(property: &Property) -> Option<&str> {
match property.value() {
MultiValues::String(values) if values.len() == 1 => values.first().map(String::as_str),
_ => None,
}
}
pub(crate) fn is_effectively_missing<R: ConfigReader + ?Sized>(
reader: &R,
name: &str,
property: &Property,
options: &ConfigReadOptions,
) -> ConfigResult<bool> {
is_effectively_missing_by(reader, name, property, options, false)
}
pub(crate) fn parse_property_from_reader<R, T>(
reader: &R,
name: &str,
property: &Property,
options: &ConfigReadOptions,
) -> ConfigResult<T>
where
R: ConfigReader + ?Sized,
T: FromConfig,
{
parse_property_from_reader_by(reader, name, property, options, false)
}
pub(crate) fn is_effectively_missing_with_substitution<R: ConfigReader + ?Sized>(
reader: &R,
name: &str,
property: &Property,
options: &ConfigReadOptions,
) -> ConfigResult<bool> {
is_effectively_missing_by(reader, name, property, options, true)
}
pub(crate) fn parse_property_from_reader_with_substitution<R, T>(
reader: &R,
name: &str,
property: &Property,
options: &ConfigReadOptions,
) -> ConfigResult<T>
where
R: ConfigReader + ?Sized,
T: FromConfig,
{
parse_property_from_reader_by(reader, name, property, options, true)
}
fn is_effectively_missing_by<R: ConfigReader + ?Sized>(
reader: &R,
name: &str,
property: &Property,
options: &ConfigReadOptions,
apply_substitution: bool,
) -> ConfigResult<bool> {
if property.is_empty() {
return Ok(true);
}
let Some(value) = first_scalar_string(property) else {
return Ok(false);
};
let substitute = |value: &str| substitute_for_reader(reader, value, apply_substitution);
let ctx = ConfigParseContext::new(name, options, &substitute);
let value = ctx.substitute_string(value)?;
match options.conversion_options().string.normalize(&value) {
Ok(_) => Ok(false),
Err(qubit_datatype::DataConversionError::NoValue) => Ok(true),
Err(_) => Ok(false),
}
}
fn parse_property_from_reader_by<R, T>(
reader: &R,
name: &str,
property: &Property,
options: &ConfigReadOptions,
apply_substitution: bool,
) -> ConfigResult<T>
where
R: ConfigReader + ?Sized,
T: FromConfig,
{
let substitute = |value: &str| substitute_for_reader(reader, value, apply_substitution);
let ctx = ConfigParseContext::new(name, options, &substitute);
T::from_config(property, &ctx)
}
fn substitute_for_reader<R: ConfigReader + ?Sized>(
reader: &R,
value: &str,
apply_substitution: bool,
) -> ConfigResult<String> {
if apply_substitution && reader.is_enable_variable_substitution() {
utils::substitute_variables(value, reader, reader.max_substitution_depth())
} else {
no_substitution(value)
}
}
fn no_substitution(value: &str) -> ConfigResult<String> {
Ok(value.to_string())
}