use crate::{ConfigError, ConfigLocation, ConfigType};
use std::{fs::read_to_string, io::Write};
pub fn load_json<T>(
app_name: impl AsRef<str>,
config_name: Option<&str>,
location: impl AsRef<ConfigLocation>,
reset_conf_on_err: bool,
) -> Result<T, ConfigError>
where
T: Default + serde::Serialize + serde::de::DeserializeOwned,
{
let config_file_path = crate::config_location(
app_name.as_ref(),
config_name,
ConfigType::Json.as_str(),
location.as_ref(),
)?;
let save_default_conf = || {
let default_config = T::default();
let json_str = serde_json::to_string_pretty(&default_config)?;
crate::save_config_str(&config_file_path, &json_str)?;
Ok(default_config)
};
if !config_file_path.try_exists()? {
return save_default_conf();
}
let json_str = read_to_string(&config_file_path)?;
let config = match serde_json::from_str::<T>(&json_str) {
Ok(config) => config,
Err(err) => {
if reset_conf_on_err {
return save_default_conf();
}
return Err(err.into());
}
};
Ok(config)
}
pub fn store_json<T>(
app_name: impl AsRef<str>,
config_name: Option<&str>,
location: impl AsRef<ConfigLocation>,
data: T,
) -> Result<(), ConfigError>
where
T: serde::Serialize,
{
let config_file_path = crate::config_location(
app_name.as_ref(),
config_name,
ConfigType::Json.as_str(),
location.as_ref(),
)?;
let mut file = std::io::BufWriter::new(std::fs::File::create(config_file_path)?);
let json_str = serde_json::to_string_pretty(&data)?;
file.write_all(json_str.as_bytes())?;
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
use serde::Deserialize;
use ConfigLocation::{Cache, Config, Cwd, LocalData};
#[derive(Default, serde::Serialize, Deserialize, PartialEq, Debug, Clone)]
struct TestConfig {
test: String,
test_vec: Vec<u8>,
}
#[test]
fn read_default_config_json() {
let config = load_json::<TestConfig>(
"test-binconf-read_default_config-string-json",
None,
Config,
false,
)
.unwrap();
assert_eq!(config, TestConfig::default());
let test_config = TestConfig {
test: String::from("test"),
test_vec: vec![1, 2, 3, 4, 5],
};
let config: TestConfig = load_json(
"test-binconf-read_default_config-struct-json",
None,
Config,
false,
)
.unwrap();
assert_eq!(config, TestConfig::default());
store_json(
"test-binconf-read_default_config-struct-json",
None,
Config,
&test_config,
)
.unwrap();
let config: TestConfig = load_json(
"test-binconf-read_default_config-struct-json",
None,
Config,
false,
)
.unwrap();
assert_eq!(config, test_config);
}
#[test]
fn config_with_name_json() {
let config = load_json::<TestConfig>(
"test-binconf-config_with_name-string-json",
Some("test-config.json"),
Config,
false,
)
.unwrap();
assert_eq!(config, TestConfig::default());
let test_config = TestConfig {
test: String::from("test"),
test_vec: vec![1, 2, 3, 4, 5],
};
let config: TestConfig = load_json(
"test-binconf-config_with_name-struct-json",
Some("test-config.json"),
Config,
false,
)
.unwrap();
assert_eq!(config, TestConfig::default());
store_json(
"test-binconf-config_with_name-struct-json",
Some("test-config.json"),
Config,
&test_config,
)
.unwrap();
let config: TestConfig = load_json(
"test-binconf-config_with_name-struct-json",
Some("test-config.json"),
Config,
false,
)
.unwrap();
assert_eq!(config, test_config);
}
#[test]
fn returns_error_on_invalid_config_json() {
let data = TestConfig {
test: String::from("test"),
test_vec: vec![1, 2, 3, 4, 5],
};
store_json(
"test-binconf-returns_error_on_invalid_config-json",
None,
Config,
&data,
)
.unwrap();
let config = load_json::<String>(
"test-binconf-returns_error_on_invalid_config-json",
None,
Config,
false,
);
assert!(config.is_err());
}
#[test]
fn save_config_user_config_json() {
let data = TestConfig {
test: String::from("test"),
test_vec: vec![1, 2, 3, 4, 5],
};
store_json(
"test-binconf-save_config_user_config-json",
None,
Config,
&data,
)
.unwrap();
let config: TestConfig = load_json(
"test-binconf-save_config_user_config-json",
None,
Config,
false,
)
.unwrap();
assert_eq!(config, data);
}
#[test]
fn save_config_user_cache_json() {
let data = TestConfig {
test: String::from("test"),
test_vec: vec![1, 2, 3, 4, 5],
};
store_json(
"test-binconf-save_config_user_cache-json",
None,
Cache,
&data,
)
.unwrap();
let config: TestConfig = load_json(
"test-binconf-save_config_user_cache-json",
None,
Cache,
false,
)
.unwrap();
assert_eq!(config, data);
}
#[test]
fn save_config_user_local_data_json() {
let data = TestConfig {
test: String::from("test"),
test_vec: vec![1, 2, 3, 4, 5],
};
store_json(
"test-binconf-save_config_user_local_data-json",
None,
LocalData,
&data,
)
.unwrap();
let config: TestConfig = load_json(
"test-binconf-save_config_user_local_data-json",
None,
LocalData,
false,
)
.unwrap();
assert_eq!(config, data);
}
#[test]
fn save_config_user_cwd_json() {
let data = TestConfig {
test: String::from("test"),
test_vec: vec![1, 2, 3, 4, 5],
};
store_json("test-binconf-save_config_user_cwd-json", None, Cwd, &data).unwrap();
let config: TestConfig =
load_json("test-binconf-save_config_user_cwd-json", None, Cwd, false).unwrap();
assert_eq!(config, data);
}
}