mod builder;
mod service;
use std::fmt;
use std::path::PathBuf;
use serde::de::DeserializeOwned;
use crate::config::LoadOptions;
use crate::domain::{Format, ParsedContent, Result};
pub use builder::{CascadeLayerBuilder, CascadeLoaderBuilder};
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum CascadeScope {
System,
Global,
User,
Local,
Worktree,
Custom(String),
}
impl fmt::Display for CascadeScope {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::System => write!(f, "system"),
Self::Global => write!(f, "global"),
Self::User => write!(f, "user"),
Self::Local => write!(f, "local"),
Self::Worktree => write!(f, "worktree"),
Self::Custom(scope) => write!(f, "{scope}"),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct CascadeLayer {
pub scope: CascadeScope,
pub path: PathBuf,
pub optional: bool,
pub priority: i32,
pub format: Option<Format>,
}
impl CascadeLayer {
#[must_use]
pub fn new(scope: CascadeScope, path: impl Into<PathBuf>) -> Self {
Self {
priority: 0,
scope,
path: path.into(),
optional: false,
format: None,
}
}
#[must_use]
pub fn builder() -> CascadeLayerBuilder {
CascadeLayerBuilder::new()
}
#[must_use]
pub const fn optional(mut self, optional: bool) -> Self {
self.optional = optional;
self
}
#[must_use]
pub const fn priority(mut self, priority: i32) -> Self {
self.priority = priority;
self
}
#[must_use]
pub const fn format(mut self, format: Format) -> Self {
self.format = Some(format);
self
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ResolvedCascadeLayer {
pub scope: CascadeScope,
pub path: PathBuf,
pub priority: i32,
}
impl From<&CascadeLayer> for ResolvedCascadeLayer {
fn from(layer: &CascadeLayer) -> Self {
Self {
scope: layer.scope.clone(),
path: layer.path.clone(),
priority: layer.priority,
}
}
}
#[derive(Debug, Clone)]
pub struct CascadeLoadResult {
pub content: ParsedContent,
pub loaded_layers: Vec<ResolvedCascadeLayer>,
pub skipped_layers: Vec<ResolvedCascadeLayer>,
pub failed_layers: Vec<(ResolvedCascadeLayer, String)>,
pub processing_time_ms: u64,
}
impl CascadeLoadResult {
#[must_use]
pub const fn content(&self) -> &ParsedContent {
&self.content
}
pub fn to_type<T: DeserializeOwned>(&self) -> Result<T> {
self.content.to_type()
}
}
#[derive(Debug, Clone, Default)]
pub struct CascadeLoader {
pub(super) layers: Vec<CascadeLayer>,
pub(super) options: LoadOptions,
pub(super) default_format: Option<Format>,
}
impl CascadeLoader {
#[must_use]
pub fn new() -> Self {
Self::default()
}
#[must_use]
pub fn builder() -> CascadeLoaderBuilder {
CascadeLoaderBuilder::new()
}
}
#[cfg(test)]
mod tests;