use crate::{util::fmt_debug_view, *}; use cfg_if::cfg_if; use std::any::Any; use std::borrow::Borrow; use std::collections::{HashMap, HashSet}; use std::fmt::{Debug, Formatter, Result as FormatResult}; use std::ops::Deref; use tokens::{ChangeToken, CompositeChangeToken, SharedChangeToken}; cfg_if! { if #[cfg(feature = "async")] { use std::sync::Arc; type Pc = std::sync::Arc; type Mut = std::sync::RwLock; type Ref<'a, T> = Arc>; } else { use std::cell::Ref; type Pc = std::rc::Rc; type Mut = std::cell::RefCell; } } struct ProviderItem<'a> { index: usize, name: String, items: Ref<'a, Vec>>, } impl<'a> ProviderItem<'a> { fn new( items: Ref<'a, Vec>>, index: usize, name: String, ) -> Self { Self { index, name, items } } } impl ConfigurationProvider for ProviderItem<'_> { fn get(&self, key: &str) -> Option { self.items[self.index].get(key) } fn child_keys(&self, earlier_keys: &mut Vec, parent_path: Option<&str>) { self.items[self.index].child_keys(earlier_keys, parent_path) } fn name(&self) -> &str { &self.name } fn reload_token(&self) -> Box { self.items[self.index].reload_token() } } struct ProviderIter<'a> { head: usize, tail: usize, items: Ref<'a, Vec>>, } impl<'a> ProviderIter<'a> { fn new(items: Ref<'a, Vec>>) -> Self { Self { head: 0, tail: items.len(), items, } } } impl<'a> Iterator for ProviderIter<'a> { type Item = Box; fn next(&mut self) -> Option { if self.head < self.items.len() { let i = self.head; let name = self.items[i].name().to_owned(); self.head += 1; cfg_if! { if #[cfg(feature = "async")] { Some(Box::new(ProviderItem::new( self.items.clone(), i, name, ))) } else { Some(Box::new(ProviderItem::new( Ref::clone(&self.items), i, name, ))) } } } else { None } } } impl ExactSizeIterator for ProviderIter<'_> { fn len(&self) -> usize { self.items.len() } } impl DoubleEndedIterator for ProviderIter<'_> { fn next_back(&mut self) -> Option { if self.tail > 0 { self.tail -= 1; let name = self.items[self.tail].name().to_owned(); cfg_if! { if #[cfg(feature = "async")] { Some(Box::new(ProviderItem::new( self.items.clone(), self.tail, name, ))) } else { Some(Box::new(ProviderItem::new( Ref::clone(&self.items), self.tail, name, ))) } } } else { None } } } impl<'a> ConfigurationProviderIterator<'a> for ProviderIter<'a> {} /// Represents the root of a configuration. #[derive(Clone)] pub struct DefaultConfigurationRoot { token: SharedChangeToken, providers: Pc>>>, } impl DefaultConfigurationRoot { /// Initializes a new root configuration. /// /// # Arguments /// /// * `providers` - The [`ConfigurationProvider`](crate::ConfigurationProvider) list used in the configuration pub fn new(mut providers: Vec>) -> Result { let mut errors = Vec::new(); let mut tokens = Vec::with_capacity(providers.len()); for provider in providers.iter_mut() { let result = provider.load(); if let Err(error) = result { errors.push((provider.name().to_owned(), error)); } tokens.push(provider.reload_token()); } if errors.is_empty() { Ok(Self { token: SharedChangeToken::new(CompositeChangeToken::new(tokens.into_iter())), providers: Pc::new(providers.into()), }) } else { Err(ReloadError::Provider(errors)) } } } impl ConfigurationRoot for DefaultConfigurationRoot { fn reload(&mut self) -> ReloadResult { let borrowed = (Pc::strong_count(&self.providers) - 1) + Pc::weak_count(&self.providers); cfg_if! { if #[cfg(feature = "async")] { let result = self.providers.try_write(); } else { let result = self.providers.try_borrow_mut(); } } if let Ok(mut providers) = result { let mut errors = Vec::new(); let mut tokens = Vec::with_capacity(providers.len()); for provider in providers.iter_mut() { let result = provider.load(); if let Err(error) = result { errors.push((provider.name().to_owned(), error)); } tokens.push(provider.reload_token()); } let new_token = SharedChangeToken::new(CompositeChangeToken::new(tokens.into_iter())); let old_token = std::mem::replace(&mut self.token, new_token); old_token.notify(); if errors.is_empty() { Ok(()) } else { Err(ReloadError::Provider(errors)) } } else { Err(ReloadError::Borrowed(Some(borrowed))) } } fn providers(&self) -> Box { cfg_if! { if #[cfg(feature = "async")] { Box::new(ProviderIter::new(self.providers.deref().read().unwrap().into())) } else { Box::new(ProviderIter::new(self.providers.deref().borrow())) } } } fn as_config(&self) -> Box { Box::new(self.clone()) } } impl Configuration for DefaultConfigurationRoot { fn get(&self, key: &str) -> Option { for provider in self.providers().rev() { if let Some(value) = provider.get(key) { return Some(value); } } None } fn section(&self, key: &str) -> Box { Box::new(DefaultConfigurationSection::new( Box::new(self.clone()), key, )) } fn children(&self) -> Vec> { self.providers() .fold(Vec::new(), |mut earlier_keys, provider| { provider.child_keys(&mut earlier_keys, None); earlier_keys }) .into_iter() .collect::>() .iter() .map(|key| self.section(key)) .collect() } fn reload_token(&self) -> Box { Box::new(self.token.clone()) } fn iter(&self, path: Option) -> Box> { Box::new(ConfigurationIterator::new( self, path.unwrap_or(ConfigurationPath::Absolute), )) } } impl Debug for DefaultConfigurationRoot { fn fmt(&self, formatter: &mut Formatter<'_>) -> FormatResult { fmt_debug_view(self, formatter) } } impl<'a> AsRef for DefaultConfigurationRoot { fn as_ref(&self) -> &(dyn Configuration + 'a) { self } } impl<'a> Borrow for DefaultConfigurationRoot { fn borrow(&self) -> &(dyn Configuration + 'a) { self } } impl Deref for DefaultConfigurationRoot { type Target = dyn Configuration; fn deref(&self) -> &Self::Target { self } } cfg_if! { if #[cfg(feature = "async")] { unsafe impl Send for DefaultConfigurationRoot {} unsafe impl Sync for DefaultConfigurationRoot {} } } /// Represent a configuration section. #[derive(Clone)] pub struct DefaultConfigurationSection { root: Pc, path: String, } impl DefaultConfigurationSection { /// Initializes a new configuration section. /// /// # Arguments /// /// * `root` - A reference to the [`ConfigurationRoot`](crate::ConfigurationRoot) /// * `path` - The path of the configuration section pub fn new(root: Box, path: &str) -> Self { Self { root: root.into(), path: path.to_owned(), } } #[inline] fn subkey(&self, key: &str) -> String { ConfigurationPath::combine(&[&self.path, key]) } } impl Configuration for DefaultConfigurationSection { fn get(&self, key: &str) -> Option { self.root.get(&self.subkey(key)) } fn section(&self, key: &str) -> Box { self.root.section(&self.subkey(key)) } fn children(&self) -> Vec> { self.root .providers() .fold(Vec::new(), |mut earlier_keys, provider| { provider.child_keys(&mut earlier_keys, Some(&self.path)); earlier_keys }) .into_iter() .collect::>() .iter() .map(|key| self.section(key)) .collect() } fn reload_token(&self) -> Box { self.root.reload_token() } fn as_section(&self) -> Option<&dyn ConfigurationSection> { Some(self) } fn iter(&self, path: Option) -> Box> { Box::new(ConfigurationIterator::new( self, path.unwrap_or(ConfigurationPath::Absolute), )) } } impl ConfigurationSection for DefaultConfigurationSection { fn key(&self) -> &str { ConfigurationPath::section_key(&self.path) } fn path(&self) -> &str { &self.path } fn value(&self) -> Value { self.root.get(&self.path).unwrap_or_default() } fn as_config(&self) -> Box { Box::new(self.clone()) } } impl<'a> AsRef for DefaultConfigurationSection { fn as_ref(&self) -> &(dyn Configuration + 'a) { self } } impl<'a> Borrow for DefaultConfigurationSection { fn borrow(&self) -> &(dyn Configuration + 'a) { self } } impl Deref for DefaultConfigurationSection { type Target = dyn Configuration; fn deref(&self) -> &Self::Target { self } } /// Represents a configuration builder. #[derive(Default)] pub struct DefaultConfigurationBuilder { /// Gets the associated configuration sources. pub sources: Vec>, /// Gets the properties that can be passed to configuration sources. pub properties: HashMap>, } impl DefaultConfigurationBuilder { /// Initializes a new, default configuration builder. pub fn new() -> Self { Self::default() } } impl ConfigurationBuilder for DefaultConfigurationBuilder { fn properties(&self) -> &HashMap> { &self.properties } fn sources(&self) -> &[Box] { &self.sources } fn add(&mut self, source: Box) { self.sources.push(source) } fn build(&self) -> Result, ReloadError> { Ok(Box::new(DefaultConfigurationRoot::new( self.sources.iter().map(|s| s.build(self)).collect(), )?)) } }