config_more_formats/
lib.rs1#[cfg(feature = "hjson")]
52mod hjson;
53
54#[cfg(feature = "hjson")]
55pub use hjson::Hjson;
56use std::error::Error;
57#[cfg(feature = "properties")]
58mod properties;
59#[cfg(feature = "properties")]
60pub use properties::Properties;
61mod util;
62
63#[cfg(feature = "hcl")]
64mod hcl;
65#[cfg(feature = "hcl")]
66pub use hcl::Hcl;
67#[cfg(feature = "ason")]
68mod ason;
69#[cfg(feature = "ason")]
70pub use ason::Ason;
71#[cfg(feature = "yaml_ng")]
72mod yaml_ng;
73#[cfg(feature = "yaml_ng")]
74pub use yaml_ng::YamlNg;
75
76use config::{FileFormat, FileSourceFile, FileStoredFormat, Format, Map, Value};
77use std::fmt::Display;
78use std::path::Path;
79
80#[derive(Debug)]
84pub enum FormatError {
85 NoExtensionFound,
87 UnsupportedFormat(String),
89}
90
91impl Display for FormatError {
92 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
93 match self {
94 FormatError::NoExtensionFound => write!(f, "No file extension found"),
95 FormatError::UnsupportedFormat(ext) => write!(f, "Unsupported file format: {}", ext),
96 }
97 }
98}
99
100impl Error for FormatError {}
101
102pub fn by_file_extension(file: &str) -> Result<config::File<FileSourceFile, FormatWrapper>, FormatError> {
107 let ext = Path::new(file);
108 let ext = ext.extension();
109 let ext = ext.ok_or(FormatError::NoExtensionFound)?;
110 let ext = ext.to_string_lossy();
111 let ext = ext.to_string();
112
113 match ext.as_str() {
114 #[cfg(feature = "toml")]
116 "toml" => Ok(config::File::new(file, config::FileFormat::Toml.into())),
117 #[cfg(feature = "json")]
118 "json" => Ok(config::File::new(file, config::FileFormat::Json.into())),
119 #[cfg(feature = "yaml")]
120 "yaml" | "yml" => Ok(config::File::new(file, config::FileFormat::Yaml.into())),
121 #[cfg(feature = "ron")]
122 "ron" => Ok(config::File::new(file, config::FileFormat::Ron.into())),
123 #[cfg(feature = "json5")]
124 "json5" => Ok(config::File::new(file, config::FileFormat::Json5.into())),
125 #[cfg(feature = "ini")]
126 "ini" => Ok(config::File::new(file, config::FileFormat::Ini.into())),
127
128 #[cfg(feature = "hjson")]
130 "hjson" => Ok(config::File::new(file, FormatWrapper::Hjson)),
131 #[cfg(feature = "properties")]
132 "properties" => Ok(config::File::new(file, FormatWrapper::Properties)),
133 #[cfg(feature = "yaml_ng")]
134 "yaml_ng" => Ok(config::File::new(file, FormatWrapper::YamlNg)),
135 #[cfg(feature = "hcl")]
136 "hcl" => Ok(config::File::new(file, FormatWrapper::Hcl)),
137 #[cfg(feature = "ason")]
138 "ason" => Ok(config::File::new(file, FormatWrapper::Ason)),
139 #[cfg(all(feature = "yaml_ng", not(feature = "yaml")))]
140 "yaml" | "yml" => Ok(config::File::new(file, FormatWrapper::YamlNg)),
141
142 _ => Err(FormatError::UnsupportedFormat(ext)),
143 }
144}
145
146#[derive(Debug, Clone)]
147pub enum FormatWrapper {
148 Enum(FileFormat),
149 #[cfg(feature = "ason")]
150 Ason,
151 #[cfg(feature = "hcl")]
152 Hcl,
153 #[cfg(feature = "hjson")]
154 Hjson,
155 #[cfg(feature = "properties")]
156 Properties,
157 #[cfg(feature = "yaml_ng")]
158 YamlNg,
159}
160
161impl Format for FormatWrapper {
162 fn parse(&self, uri: Option<&String>, text: &str) -> Result<Map<String, Value>, Box<dyn Error + Send + Sync>> {
163 match self {
164 FormatWrapper::Enum(f) => f.parse(uri, text),
165 #[cfg(feature = "ason")]
166 FormatWrapper::Ason => Ason.parse(uri, text),
167 #[cfg(feature = "hcl")]
168 FormatWrapper::Hcl => Hcl.parse(uri, text),
169 #[cfg(feature = "hjson")]
170 FormatWrapper::Hjson => Hjson.parse(uri, text),
171 #[cfg(feature = "properties")]
172 FormatWrapper::Properties => Properties.parse(uri, text),
173 #[cfg(feature = "yaml_ng")]
174 FormatWrapper::YamlNg => YamlNg.parse(uri, text),
175 }
176 }
177}
178
179impl FileStoredFormat for FormatWrapper {
180 fn file_extensions(&self) -> &'static [&'static str] {
181 match self {
182 FormatWrapper::Enum(f) => f.file_extensions(),
183 #[cfg(feature = "ason")]
184 FormatWrapper::Ason => Ason.file_extensions(),
185 #[cfg(feature = "hcl")]
186 FormatWrapper::Hcl => Hcl.file_extensions(),
187 #[cfg(feature = "hjson")]
188 FormatWrapper::Hjson => Hjson.file_extensions(),
189 #[cfg(feature = "properties")]
190 FormatWrapper::Properties => Properties.file_extensions(),
191 #[cfg(feature = "yaml_ng")]
192 FormatWrapper::YamlNg => YamlNg.file_extensions(),
193 }
194 }
195}
196
197impl From<FileFormat> for FormatWrapper {
198 fn from(f: FileFormat) -> Self {
199 FormatWrapper::Enum(f)
200 }
201}
202
203#[cfg(feature = "ason")]
204impl From<Ason> for FormatWrapper {
205 fn from(_: Ason) -> Self {
206 FormatWrapper::Ason
207 }
208}
209
210#[cfg(feature = "hcl")]
211impl From<Hcl> for FormatWrapper {
212 fn from(_: Hcl) -> Self {
213 FormatWrapper::Hcl
214 }
215}
216
217#[cfg(feature = "hjson")]
218impl From<Hjson> for FormatWrapper {
219 fn from(_: Hjson) -> Self {
220 FormatWrapper::Hjson
221 }
222}
223
224#[cfg(feature = "properties")]
225impl From<Properties> for FormatWrapper {
226 fn from(_: Properties) -> Self {
227 FormatWrapper::Properties
228 }
229}
230
231#[cfg(feature = "yaml_ng")]
232impl From<YamlNg> for FormatWrapper {
233 fn from(_: YamlNg) -> Self {
234 FormatWrapper::YamlNg
235 }
236}
237
238#[cfg(test)]
239mod tests {
240 use super::*;
241
242 #[test]
243 fn test_by_file_extension_toml() {
244 #[cfg(feature = "toml")]
245 {
246 let result = by_file_extension("settings.toml");
247 assert!(result.is_ok());
248 }
249 }
250
251 #[test]
252 fn test_by_file_extension_json() {
253 #[cfg(feature = "json")]
254 {
255 let result = by_file_extension("settings.json");
256 assert!(result.is_ok());
257 }
258 }
259
260 #[test]
261 fn test_by_file_extension_yaml() {
262 #[cfg(feature = "yaml")]
263 {
264 let result = by_file_extension("settings.yaml");
265 assert!(result.is_ok());
266 }
267 }
268
269 #[test]
270 fn test_by_file_extension_unsupported() {
271 let result = by_file_extension("settings.unsupported");
272 assert!(matches!(result, Err(FormatError::UnsupportedFormat(_))));
273 }
274
275 #[test]
276 fn test_by_file_extension_no_extension() {
277 let result = by_file_extension("settings");
278 assert!(matches!(result, Err(FormatError::NoExtensionFound)));
279 }
280
281 #[test]
282 fn test_by_file_extension_properties() {
283 #[cfg(feature = "properties")]
284 {
285 let result = by_file_extension("settings.properties");
286 assert!(result.is_ok());
287 }
288 }
289
290 #[test]
291 fn test_by_file_extension_hjson() {
292 #[cfg(feature = "hjson")]
293 {
294 let result = by_file_extension("settings.hjson");
295 assert!(result.is_ok());
296 }
297 }
298
299 #[test]
300 fn test_by_file_extension_hcl() {
301 #[cfg(feature = "hcl")]
302 {
303 let result = by_file_extension("settings.hcl");
304 assert!(result.is_ok());
305 }
306 }
307
308 #[test]
309 fn test_by_file_extension_ason() {
310 #[cfg(feature = "ason")]
311 {
312 let result = by_file_extension("settings.ason");
313 assert!(result.is_ok());
314 }
315 }
316}