#![allow(private_bounds)]
use qubit_value::MultiValues;
use qubit_value::multi_values::{MultiValuesFirstGetter, MultiValuesGetter};
use serde::de::DeserializeOwned;
use crate::config_prefix_view::ConfigPrefixView;
use crate::field::ConfigField;
use crate::from::{FromConfig, is_effectively_missing, parse_property_from_reader};
use crate::options::ConfigReadOptions;
use crate::{Config, ConfigError, ConfigResult, Property};
pub trait ConfigReader {
fn is_enable_variable_substitution(&self) -> bool;
fn max_substitution_depth(&self) -> usize;
fn description(&self) -> Option<&str>;
fn get_property(&self, name: &str) -> Option<&Property>;
fn len(&self) -> usize;
fn is_empty(&self) -> bool;
fn keys(&self) -> Vec<String>;
fn contains(&self, name: &str) -> bool;
fn get<T>(&self, name: &str) -> ConfigResult<T>
where
T: FromConfig,
{
let resolved = self.resolve_key(name);
let property = self
.get_property(name)
.ok_or_else(|| ConfigError::PropertyNotFound(resolved.clone()))?;
if !property.is_empty()
&& is_effectively_missing(self, &resolved, property, self.read_options())?
{
return Err(ConfigError::PropertyHasNoValue(resolved));
}
parse_property_from_reader(self, &resolved, property, self.read_options())
}
fn get_strict<T>(&self, name: &str) -> ConfigResult<T>
where
MultiValues: MultiValuesFirstGetter<T>;
fn get_list<T>(&self, name: &str) -> ConfigResult<Vec<T>>
where
T: FromConfig;
fn get_list_strict<T>(&self, name: &str) -> ConfigResult<Vec<T>>
where
MultiValues: MultiValuesGetter<T>;
#[inline]
fn get_or<T>(&self, name: &str, default: T) -> ConfigResult<T>
where
T: FromConfig,
{
self.get_optional(name)
.map(|value| value.unwrap_or(default))
}
fn get_optional<T>(&self, name: &str) -> ConfigResult<Option<T>>
where
T: FromConfig,
{
let resolved = self.resolve_key(name);
match self.get_property(name) {
None => Ok(None),
Some(property)
if is_effectively_missing(self, &resolved, property, self.read_options())? =>
{
Ok(None)
}
Some(property) => {
parse_property_from_reader(self, &resolved, property, self.read_options()).map(Some)
}
}
}
fn read_options(&self) -> &ConfigReadOptions;
fn get_any<T>(&self, names: &[&str]) -> ConfigResult<T>
where
T: FromConfig,
{
self.get_optional_any(names)?
.ok_or_else(|| ConfigError::PropertyNotFound(format!("one of: {}", names.join(", "))))
}
fn get_optional_any<T>(&self, names: &[&str]) -> ConfigResult<Option<T>>
where
T: FromConfig,
{
self.get_optional_any_with_options(names, self.read_options())
}
fn get_any_or<T>(&self, names: &[&str], default: T) -> ConfigResult<T>
where
T: FromConfig,
{
self.get_optional_any(names)
.map(|value| value.unwrap_or(default))
}
fn get_any_or_with<T>(
&self,
names: &[&str],
default: T,
read_options: &ConfigReadOptions,
) -> ConfigResult<T>
where
T: FromConfig,
{
self.get_optional_any_with_options(names, read_options)
.map(|value| value.unwrap_or(default))
}
fn read<T>(&self, field: ConfigField<T>) -> ConfigResult<T>
where
T: FromConfig,
{
let ConfigField {
name,
aliases,
default,
read_options,
} = field;
let options = read_options.as_ref().unwrap_or_else(|| self.read_options());
let mut names = Vec::with_capacity(1 + aliases.len());
names.push(name.as_str());
names.extend(aliases.iter().map(String::as_str));
self.get_optional_any_with_options(&names, options)?
.or(default)
.ok_or_else(|| ConfigError::PropertyNotFound(format!("one of: {}", names.join(", "))))
}
fn read_optional<T>(&self, field: ConfigField<T>) -> ConfigResult<Option<T>>
where
T: FromConfig,
{
let ConfigField {
name,
aliases,
default,
read_options,
} = field;
let options = read_options.as_ref().unwrap_or_else(|| self.read_options());
let mut names = Vec::with_capacity(1 + aliases.len());
names.push(name.as_str());
names.extend(aliases.iter().map(String::as_str));
self.get_optional_any_with_options(&names, options)
.map(|value| value.or(default))
}
fn get_optional_any_with_options<T>(
&self,
names: &[&str],
options: &ConfigReadOptions,
) -> ConfigResult<Option<T>>
where
T: FromConfig,
{
for name in names {
let Some(property) = self.get_property(name) else {
continue;
};
let resolved = self.resolve_key(name);
if is_effectively_missing(self, &resolved, property, options)? {
continue;
}
return parse_property_from_reader(self, &resolved, property, options).map(Some);
}
Ok(None)
}
fn get_optional_list<T>(&self, name: &str) -> ConfigResult<Option<Vec<T>>>
where
T: FromConfig;
fn contains_prefix(&self, prefix: &str) -> bool;
fn iter_prefix<'a>(
&'a self,
prefix: &'a str,
) -> Box<dyn Iterator<Item = (&'a str, &'a Property)> + 'a>;
fn iter<'a>(&'a self) -> Box<dyn Iterator<Item = (&'a str, &'a Property)> + 'a>;
fn is_null(&self, name: &str) -> bool;
fn subconfig(&self, prefix: &str, strip_prefix: bool) -> ConfigResult<Config>;
fn deserialize<T>(&self, prefix: &str) -> ConfigResult<T>
where
T: DeserializeOwned;
fn prefix_view(&self, prefix: &str) -> ConfigPrefixView<'_>;
#[inline]
fn resolve_key(&self, name: &str) -> String {
name.to_string()
}
fn get_string(&self, name: &str) -> ConfigResult<String> {
self.get(name)
}
#[inline]
fn get_string_any(&self, names: &[&str]) -> ConfigResult<String> {
self.get_any(names)
}
#[inline]
fn get_optional_string_any(&self, names: &[&str]) -> ConfigResult<Option<String>> {
self.get_optional_any(names)
}
#[inline]
fn get_string_any_or(&self, names: &[&str], default: &str) -> ConfigResult<String> {
self.get_any_or(names, default.to_string())
}
#[inline]
fn get_string_or(&self, name: &str, default: &str) -> ConfigResult<String> {
self.get_or(name, default.to_string())
}
fn get_string_list(&self, name: &str) -> ConfigResult<Vec<String>> {
self.get(name)
}
#[inline]
fn get_string_list_or(&self, name: &str, default: &[&str]) -> ConfigResult<Vec<String>> {
self.get_or(name, default.iter().map(|s| s.to_string()).collect())
}
#[inline]
fn get_optional_string(&self, name: &str) -> ConfigResult<Option<String>> {
match self.get_property(name) {
None => Ok(None),
Some(prop) if prop.is_empty() => Ok(None),
Some(_) => self.get_string(name).map(Some),
}
}
#[inline]
fn get_optional_string_list(&self, name: &str) -> ConfigResult<Option<Vec<String>>> {
match self.get_property(name) {
None => Ok(None),
Some(prop) if prop.is_empty() => Ok(None),
Some(_) => self.get_string_list(name).map(Some),
}
}
}