tier 0.1.17

Rust configuration library for layered TOML, env, and CLI settings
Documentation
use serde::Serialize;
use serde::de::DeserializeOwned;

use crate::error::ConfigError;

use super::LoadSession;
use crate::loader::env_decoder::{canonicalize_custom_env_decoders, canonicalize_env_decoders};
use crate::loader::file::load_file_layer;
use crate::loader::merge::merged_shape_from_layers;
use crate::loader::{Layer, PendingCustomLayer, SourceKind, SourceTrace};

impl<T> LoadSession<T>
where
    T: Serialize + DeserializeOwned,
{
    pub(super) fn collect_layers(&mut self) -> Result<(), ConfigError> {
        self.add_default_layer()?;
        self.add_file_layers()?;
        self.add_custom_layers()?;
        self.prepare_env_metadata()?;
        self.add_env_layers()?;
        self.add_arg_layers()?;
        self.add_typed_arg_layers()
    }

    fn add_default_layer(&mut self) -> Result<(), ConfigError> {
        let layer = Layer::from_serializable(
            SourceTrace::new(SourceKind::Default, "defaults"),
            &self.defaults,
        )?;
        self.push_canonical_layer(layer)
    }

    fn add_file_layers(&mut self) -> Result<(), ConfigError> {
        let mut files = std::mem::take(&mut self.files);
        if let Some(parsed) = &self.parsed_args {
            files.extend(parsed.files.clone());
        }

        for file in files {
            if let Some(layer) = load_file_layer(file, self.profile.as_deref())? {
                self.push_canonical_layer(layer)?;
            }
        }

        Ok(())
    }

    fn add_custom_layers(&mut self) -> Result<(), ConfigError> {
        for pending in std::mem::take(&mut self.custom_layers) {
            self.recanonicalize_metadata()?;
            let layer = match pending {
                PendingCustomLayer::Immediate(layer) => layer,
                PendingCustomLayer::DeferredPatch(patch) => patch.into_layer_with_shape(
                    merged_shape_from_layers(&self.defaults_shape, &self.layers, &self.metadata)?,
                )?,
            };
            self.push_canonical_layer(layer)?;
        }

        Ok(())
    }

    fn prepare_env_metadata(&mut self) -> Result<(), ConfigError> {
        self.recanonicalize_metadata()?;
        let _ = self.metadata.env_overrides()?;
        Ok(())
    }

    fn add_env_layers(&mut self) -> Result<(), ConfigError> {
        for env_source in std::mem::take(&mut self.env_sources) {
            self.recanonicalize_metadata()?;
            let env_decoders =
                canonicalize_env_decoders(&self.env_decoders, &self.metadata, &self.layers)?;
            let custom_env_decoders = canonicalize_custom_env_decoders(
                &self.custom_env_decoders,
                &self.metadata,
                &self.layers,
            )?;
            if let Some(layer) = env_source.into_layer(
                &self.metadata,
                &env_decoders,
                &custom_env_decoders,
                &self.layers,
            )? {
                self.push_canonical_layer(layer)?;
            }
        }

        Ok(())
    }

    fn add_arg_layers(&mut self) -> Result<(), ConfigError> {
        if let Some(layer) = self.parsed_args.take().and_then(|parsed| parsed.layer) {
            self.push_canonical_layer(layer)?;
        }

        Ok(())
    }

    fn add_typed_arg_layers(&mut self) -> Result<(), ConfigError> {
        for patch in std::mem::take(&mut self.typed_arg_layers) {
            self.recanonicalize_metadata()?;
            let layer = patch.into_layer_with_shape(merged_shape_from_layers(
                &self.defaults_shape,
                &self.layers,
                &self.metadata,
            )?)?;
            self.push_canonical_layer(layer)?;
        }

        Ok(())
    }
}