1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
use {
crate::math::Extent,
app_dirs::{get_app_root, AppDataType, AppDirsError, AppInfo},
serde::{Deserialize, Serialize},
std::{
fs::{create_dir_all, read_to_string, File},
io::{Error as IoError, ErrorKind, Write},
path::PathBuf,
},
toml::{from_str, to_string_pretty},
};
#[cfg(debug_assertions)]
const CONFIG_FILENAME: &str = "engine-debug.toml";
#[cfg(not(debug_assertions))]
const CONFIG_FILENAME: &str = "engine.toml";
pub fn get_program_root(name: &'static str, author: &'static str) -> Result<PathBuf, IoError> {
match get_app_root(AppDataType::UserConfig, &AppInfo { name, author }) {
Err(err) => Err(match err {
AppDirsError::Io(err) => err,
AppDirsError::InvalidAppInfo => IoError::from(ErrorKind::InvalidInput),
AppDirsError::NotSupported => IoError::from(ErrorKind::InvalidData),
}),
Ok(res) => Ok(res),
}
}
fn get_config_path(name: &'static str, author: &'static str) -> Result<PathBuf, IoError> {
let program_root = get_program_root(name, author)?;
Ok(program_root.join(CONFIG_FILENAME))
}
pub struct Config {
data: Data,
program_author: &'static str,
program_name: &'static str,
}
#[derive(Clone, Default, Deserialize, Serialize)]
struct Data {
fullscreen: Option<bool>,
swapchain_len: Option<u32>,
window_dimensions: Option<(usize, usize)>,
}
impl Config {
pub fn read(program_name: &'static str, program_author: &'static str) -> Result<Self, IoError> {
let config_path = get_config_path(program_name, program_author)?;
Ok(if config_path.exists() {
#[cfg(debug_assertions)]
debug!("Loaded config {}", config_path.display());
let config_file = read_to_string(&*config_path).unwrap_or_else(|_| {
#[cfg(debug_assertions)]
warn!("Engine config file read error, creating a new one");
"".to_owned()
});
let config: Schema = from_str(&config_file).unwrap_or_default();
Self {
data: config.data,
program_author,
program_name,
}
} else {
#[cfg(debug_assertions)]
info!("Engine config file not found, creating a new one");
let mut res = Self {
data: Data::default(),
program_author,
program_name,
};
res.data.fullscreen = None;
res.data.swapchain_len = Some(res.swapchain_len());
res.data.window_dimensions = None;
res.write()?;
res
})
}
pub fn fullscreen(&self) -> Option<bool> {
self.data.fullscreen
}
pub fn swapchain_len(&self) -> u32 {
self.data.swapchain_len.unwrap_or(3).max(1).min(3)
}
pub fn window_dimensions(&self) -> Extent {
self.data
.window_dimensions
.map(|dims| Extent::new(dims.0 as _, dims.1 as _))
.unwrap_or_else(|| Extent::new(1920, 1080))
}
pub fn write(&self) -> Result<(), IoError> {
let program_root = get_program_root(self.program_name, self.program_author)?;
if !program_root.exists() {
create_dir_all(&*program_root)?;
}
let config_path = get_config_path(self.program_name, self.program_author)?;
let mut config_file = File::create(&*config_path)?;
let toml = to_string_pretty(&Schema {
data: self.data.clone(),
});
if toml.is_err() {
return Err(IoError::from(ErrorKind::Other));
}
let toml = toml.unwrap();
config_file.write_all(toml.as_bytes())?;
Ok(())
}
}
#[derive(Default, Deserialize, Serialize)]
struct Schema {
#[serde(rename = "screen-13")]
data: Data,
}