#![allow(private_bounds)]
use std::collections::HashMap;
use serde::{Deserialize, Serialize};
use super::{utils, ConfigError, ConfigResult, Property};
use qubit_value::multi_values::{
MultiValuesAddArg, MultiValuesAdder, MultiValuesFirstGetter, MultiValuesGetter,
MultiValuesMultiAdder, MultiValuesSetArg, MultiValuesSetter, MultiValuesSetterSlice,
MultiValuesSingleSetter,
};
use qubit_value::MultiValues;
pub const DEFAULT_MAX_SUBSTITUTION_DEPTH: usize = 64;
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct Config {
description: Option<String>,
properties: HashMap<String, Property>,
enable_variable_substitution: bool,
max_substitution_depth: usize,
}
impl Config {
pub fn new() -> Self {
Self {
description: None,
properties: HashMap::new(),
enable_variable_substitution: true,
max_substitution_depth: DEFAULT_MAX_SUBSTITUTION_DEPTH,
}
}
pub fn with_description(description: &str) -> Self {
Self {
description: Some(description.to_string()),
properties: HashMap::new(),
enable_variable_substitution: true,
max_substitution_depth: DEFAULT_MAX_SUBSTITUTION_DEPTH,
}
}
pub fn description(&self) -> Option<&str> {
self.description.as_deref()
}
pub fn set_description(&mut self, description: Option<String>) {
self.description = description;
}
pub fn is_enable_variable_substitution(&self) -> bool {
self.enable_variable_substitution
}
pub fn set_enable_variable_substitution(&mut self, enable: bool) {
self.enable_variable_substitution = enable;
}
pub fn max_substitution_depth(&self) -> usize {
self.max_substitution_depth
}
pub fn set_max_substitution_depth(&mut self, depth: usize) {
self.max_substitution_depth = depth;
}
pub fn contains(&self, name: &str) -> bool {
self.properties.contains_key(name)
}
pub fn get_property(&self, name: &str) -> Option<&Property> {
self.properties.get(name)
}
pub fn get_property_mut(&mut self, name: &str) -> Option<&mut Property> {
self.properties.get_mut(name)
}
pub fn remove(&mut self, name: &str) -> Option<Property> {
self.properties.remove(name)
}
pub fn clear(&mut self) {
self.properties.clear();
}
pub fn len(&self) -> usize {
self.properties.len()
}
pub fn is_empty(&self) -> bool {
self.properties.is_empty()
}
pub fn keys(&self) -> Vec<String> {
self.properties.keys().cloned().collect()
}
pub fn get<T>(&self, name: &str) -> ConfigResult<T>
where
MultiValues: MultiValuesFirstGetter<T>,
{
let property = self
.properties
.get(name)
.ok_or_else(|| ConfigError::PropertyNotFound(name.to_string()))?;
property.get_first::<T>().map_err(ConfigError::from)
}
pub fn get_or<T>(&self, name: &str, default: T) -> T
where
MultiValues: MultiValuesFirstGetter<T>,
{
self.get(name).unwrap_or(default)
}
pub fn get_list<T>(&self, name: &str) -> ConfigResult<Vec<T>>
where
MultiValues: MultiValuesGetter<T>,
{
let property = self
.properties
.get(name)
.ok_or_else(|| ConfigError::PropertyNotFound(name.to_string()))?;
property.get::<T>().map_err(ConfigError::from)
}
pub fn set<S>(&mut self, name: &str, values: S) -> ConfigResult<()>
where
S: for<'a> MultiValuesSetArg<'a>,
<S as MultiValuesSetArg<'static>>::Item: Clone,
MultiValues: MultiValuesSetter<<S as MultiValuesSetArg<'static>>::Item>
+ MultiValuesSetterSlice<<S as MultiValuesSetArg<'static>>::Item>
+ MultiValuesSingleSetter<<S as MultiValuesSetArg<'static>>::Item>,
{
if let Some(prop) = self.properties.get(name) {
if prop.is_final() {
return Err(ConfigError::PropertyIsFinal(name.to_string()));
}
}
let property = self
.properties
.entry(name.to_string())
.or_insert_with(|| Property::new(name));
property.set(values).map_err(ConfigError::from)
}
pub fn add<S>(&mut self, name: &str, values: S) -> ConfigResult<()>
where
S: for<'a> MultiValuesAddArg<'a, Item = <S as MultiValuesSetArg<'static>>::Item>
+ for<'a> MultiValuesSetArg<'a>,
<S as MultiValuesSetArg<'static>>::Item: Clone,
MultiValues: MultiValuesAdder<<S as MultiValuesSetArg<'static>>::Item>
+ MultiValuesMultiAdder<<S as MultiValuesSetArg<'static>>::Item>
+ MultiValuesSetter<<S as MultiValuesSetArg<'static>>::Item>
+ MultiValuesSetterSlice<<S as MultiValuesSetArg<'static>>::Item>
+ MultiValuesSingleSetter<<S as MultiValuesSetArg<'static>>::Item>,
{
if let Some(prop) = self.properties.get(name) {
if prop.is_final() {
return Err(ConfigError::PropertyIsFinal(name.to_string()));
}
}
if let Some(property) = self.properties.get_mut(name) {
property.add(values).map_err(ConfigError::from)
} else {
let mut property = Property::new(name);
let _ = property.set(values);
self.properties.insert(name.to_string(), property);
Ok(())
}
}
pub fn get_string(&self, name: &str) -> ConfigResult<String> {
let value: String = self.get(name)?;
if self.enable_variable_substitution {
utils::substitute_variables(&value, self, self.max_substitution_depth)
} else {
Ok(value)
}
}
pub fn get_string_or(&self, name: &str, default: &str) -> String {
self.get_string(name)
.unwrap_or_else(|_| default.to_string())
}
pub fn get_string_list(&self, name: &str) -> ConfigResult<Vec<String>> {
let values: Vec<String> = self.get_list(name)?;
if self.enable_variable_substitution {
values
.into_iter()
.map(|v| utils::substitute_variables(&v, self, self.max_substitution_depth))
.collect()
} else {
Ok(values)
}
}
pub fn get_string_list_or(&self, name: &str, default: &[&str]) -> Vec<String> {
self.get_string_list(name)
.unwrap_or_else(|_| default.iter().map(|s| s.to_string()).collect())
}
}
impl Default for Config {
fn default() -> Self {
Self::new()
}
}