fluvio_types/
config_file.rs

1use std::fmt::Debug;
2use std::io::Error as IoError;
3use std::io::ErrorKind;
4use std::io::Write;
5use std::path::Path;
6use std::fs::{File, read_to_string};
7
8use tracing::debug;
9use serde::{Serialize, de::DeserializeOwned};
10use thiserror::Error;
11
12#[derive(Debug, Error)]
13pub enum LoadConfigError {
14    #[error("IoError: {0}")]
15    IoError(IoError),
16    #[error("TomlError: {0}")]
17    TomlError(toml::de::Error),
18}
19
20pub trait SaveLoadConfig {
21    fn save_to<T: AsRef<Path>>(&self, path: T) -> Result<(), IoError>;
22    fn load_from<T: AsRef<Path>>(path: T) -> Result<Self, LoadConfigError>
23    where
24        Self: Sized;
25    fn load_str(config: &str) -> Result<Self, LoadConfigError>
26    where
27        Self: Sized;
28}
29
30impl<S> SaveLoadConfig for S
31where
32    S: Serialize + DeserializeOwned + Debug,
33{
34    // save to file
35    fn save_to<T: AsRef<Path>>(&self, path: T) -> Result<(), IoError> {
36        let path_ref = path.as_ref();
37        debug!("saving config: {:#?} to: {:#?}", self, path_ref);
38        let toml = toml::to_string(self)
39            .map_err(|err| IoError::new(ErrorKind::Other, format!("{err}")))?;
40
41        let mut file = File::create(path_ref)?;
42        file.write_all(toml.as_bytes())?;
43        // On windows flush() is noop, but sync_all() calls FlushFileBuffers.
44        file.sync_all()
45    }
46
47    fn load_from<T: AsRef<Path>>(path: T) -> Result<Self, LoadConfigError> {
48        let path_ref = path.as_ref();
49        debug!(?path_ref, "loading from");
50
51        let file_str = read_to_string(path_ref).map_err(LoadConfigError::IoError)?;
52
53        let config = toml::from_str(&file_str).map_err(LoadConfigError::TomlError)?;
54        Ok(config)
55    }
56
57    fn load_str(config: &str) -> Result<Self, LoadConfigError>
58    where
59        Self: Sized,
60    {
61        let config = toml::from_str(config).map_err(LoadConfigError::TomlError)?;
62        Ok(config)
63    }
64}