kas_core/config/
format.rs1#[cfg(feature = "serde")]
9use serde::{Serialize, de::DeserializeOwned};
10use std::path::Path;
11use thiserror::Error;
12
13#[derive(Error, Debug)]
15pub enum Error {
16 #[cfg(feature = "yaml")]
17 #[error("config deserialisation failed")]
18 De(#[from] serde::de::value::Error),
19
20 #[cfg(feature = "yaml")]
21 #[error("config serialisation to YAML failed")]
22 YamlSer(#[from] serde_yaml2::ser::Errors),
23
24 #[cfg(feature = "json")]
25 #[error("config (de)serialisation to JSON failed")]
26 Json(#[from] serde_json::Error),
27
28 #[cfg(feature = "ron")]
29 #[error("config serialisation to RON failed")]
30 Ron(#[from] ron::Error),
31
32 #[cfg(feature = "ron")]
33 #[error("config deserialisation from RON failed")]
34 RonSpanned(#[from] ron::error::SpannedError),
35
36 #[cfg(feature = "toml")]
37 #[error("config deserialisation from TOML failed")]
38 TomlDe(#[from] toml::de::Error),
39
40 #[cfg(feature = "toml")]
41 #[error("config serialisation to TOML failed")]
42 TomlSer(#[from] toml::ser::Error),
43
44 #[error("error reading / writing config file")]
45 IoError(#[from] std::io::Error),
46
47 #[error("format not supported: {0}")]
48 UnsupportedFormat(Format),
49}
50
51#[non_exhaustive]
53#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash, Error)]
54pub enum Format {
55 #[default]
57 #[error("no format")]
58 None,
59
60 #[error("JSON")]
62 Json,
63
64 #[error("TOML")]
66 Toml,
67
68 #[error("YAML")]
70 Yaml,
71
72 #[error("RON")]
74 Ron,
75
76 #[error("(unknown format)")]
78 Unknown,
79}
80
81impl Format {
82 pub fn guess_from_path(path: &Path) -> Format {
90 if let Some(ext) = path.extension() {
92 if ext == "json" {
93 Format::Json
94 } else if ext == "toml" {
95 Format::Toml
96 } else if ext == "yaml" {
97 Format::Yaml
98 } else if ext == "ron" {
99 Format::Ron
100 } else {
101 Format::Unknown
102 }
103 } else {
104 Format::Unknown
105 }
106 }
107
108 #[cfg(feature = "serde")]
110 pub fn read_path<T: DeserializeOwned>(self, path: &Path) -> Result<T, Error> {
111 log::info!("read_path: path={}, format={:?}", path.display(), self);
112 match self {
113 #[cfg(feature = "json")]
114 Format::Json => {
115 let r = std::io::BufReader::new(std::fs::File::open(path)?);
116 Ok(serde_json::from_reader(r)?)
117 }
118 #[cfg(feature = "yaml")]
119 Format::Yaml => {
120 let contents = std::fs::read_to_string(path)?;
121 Ok(serde_yaml2::from_str(&contents)?)
122 }
123 #[cfg(feature = "ron")]
124 Format::Ron => {
125 let r = std::io::BufReader::new(std::fs::File::open(path)?);
126 Ok(ron::de::from_reader(r)?)
127 }
128 #[cfg(feature = "toml")]
129 Format::Toml => {
130 let contents = std::fs::read_to_string(path)?;
131 Ok(toml::from_str(&contents)?)
132 }
133 _ => {
134 let _ = path; Err(Error::UnsupportedFormat(self))
136 }
137 }
138 }
139
140 #[cfg(feature = "serde")]
142 pub fn write_path<T: Serialize>(self, path: &Path, value: &T) -> Result<(), Error> {
143 log::info!("write_path: path={}, format={:?}", path.display(), self);
144 match self {
147 #[cfg(feature = "json")]
148 Format::Json => {
149 let text = serde_json::to_string_pretty(value)?;
150 std::fs::write(path, &text)?;
151 Ok(())
152 }
153 #[cfg(feature = "yaml")]
154 Format::Yaml => {
155 let text = serde_yaml2::to_string(value)?;
156 std::fs::write(path, text)?;
157 Ok(())
158 }
159 #[cfg(feature = "ron")]
160 Format::Ron => {
161 let pretty = ron::ser::PrettyConfig::default();
162 let text = ron::ser::to_string_pretty(value, pretty)?;
163 std::fs::write(path, &text)?;
164 Ok(())
165 }
166 #[cfg(feature = "toml")]
167 Format::Toml => {
168 let content = toml::to_string(value)?;
169 std::fs::write(path, &content)?;
170 Ok(())
171 }
172 _ => {
173 let _ = (path, value); Err(Error::UnsupportedFormat(self))
175 }
176 }
177 }
178
179 #[cfg(feature = "serde")]
181 #[inline]
182 pub fn guess_and_read_path<T: DeserializeOwned>(path: &Path) -> Result<T, Error> {
183 let format = Self::guess_from_path(path);
184 format.read_path(path)
185 }
186
187 #[cfg(feature = "serde")]
189 #[inline]
190 pub fn guess_and_write_path<T: Serialize>(path: &Path, value: &T) -> Result<(), Error> {
191 let format = Self::guess_from_path(path);
192 format.write_path(path, value)
193 }
194}