muster/adapter/config/
settings.rs1use std::{fs, path::PathBuf};
2
3use super::yaml::{config_dir_path, write_config};
4use crate::domain::{config::ConfigError, port::SettingsStore, settings::Settings};
5
6const SETTINGS_FILE: &str = "settings.yml";
8const DEFAULT_SETTINGS: &str = include_str!("default_settings.yml");
11
12#[derive(Default)]
16pub struct YamlSettingsStore;
17
18impl YamlSettingsStore {
19 fn path() -> Option<PathBuf> {
21 config_dir_path(SETTINGS_FILE)
22 }
23
24 fn defaults() -> Result<Settings, ConfigError> {
26 Ok(serde_yaml_ng::from_str(DEFAULT_SETTINGS)?)
27 }
28
29 fn load_from(path: Option<PathBuf>) -> Result<Settings, ConfigError> {
32 let path = path.ok_or(ConfigError::NoConfigDir)?;
33 if !path.exists() {
34 let defaults = Self::defaults()?;
35 write_config(&path, &defaults)?;
36 return Ok(defaults);
37 }
38 let raw = fs::read_to_string(&path).map_err(|source| ConfigError::Read {
39 path: path.clone(),
40 source,
41 })?;
42 Ok(serde_yaml_ng::from_str(&raw)?)
43 }
44}
45
46impl SettingsStore for YamlSettingsStore {
47 fn load(&self) -> Result<Settings, ConfigError> {
48 Self::load_from(Self::path())
49 }
50
51 fn save(&self, settings: &Settings) -> Result<(), ConfigError> {
52 let path = Self::path().ok_or(ConfigError::NoConfigDir)?;
53 write_config(&path, settings)
54 }
55}
56
57#[cfg(test)]
58mod tests {
59 use super::*;
60
61 #[test]
62 fn no_config_directory_fails_closed() {
63 assert!(matches!(
64 YamlSettingsStore::load_from(None),
65 Err(ConfigError::NoConfigDir)
66 ));
67 }
68
69 #[test]
70 fn shipped_defaults_are_explicit_and_valid() {
71 let settings = YamlSettingsStore::defaults().unwrap();
72
73 assert!(*settings.desktop_notifications());
74 }
75}