Skip to content

Commit 35bafb9

Browse files
authored
refactor(file): Minor clean up to file discovery (#688)
2 parents 00a5109 + e6e3fcf commit 35bafb9

File tree

2 files changed

+64
-64
lines changed

2 files changed

+64
-64
lines changed

src/file/format/mod.rs

Lines changed: 41 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
1-
use std::collections::HashMap;
21
use std::error::Error;
3-
use std::sync::OnceLock;
42

53
use crate::map::Map;
64
use crate::{file::FileStoredFormat, value::Value, Format};
@@ -54,41 +52,54 @@ pub enum FileFormat {
5452
Json5,
5553
}
5654

57-
pub(crate) fn all_extensions() -> &'static HashMap<FileFormat, Vec<&'static str>> {
58-
#![allow(unused_mut)] // If no features are used, there is an "unused mut" warning in `all_extensions`
59-
60-
static ALL_EXTENSIONS: OnceLock<HashMap<FileFormat, Vec<&'static str>>> = OnceLock::new();
61-
ALL_EXTENSIONS.get_or_init(|| {
62-
let mut formats: HashMap<FileFormat, Vec<_>> = HashMap::new();
63-
64-
#[cfg(feature = "toml")]
65-
formats.insert(FileFormat::Toml, vec!["toml"]);
55+
impl FileFormat {
56+
pub(crate) fn all() -> &'static [FileFormat] {
57+
&[
58+
#[cfg(feature = "toml")]
59+
FileFormat::Toml,
60+
#[cfg(feature = "json")]
61+
FileFormat::Json,
62+
#[cfg(feature = "yaml")]
63+
FileFormat::Yaml,
64+
#[cfg(feature = "ini")]
65+
FileFormat::Ini,
66+
#[cfg(feature = "ron")]
67+
FileFormat::Ron,
68+
#[cfg(feature = "json5")]
69+
FileFormat::Json5,
70+
]
71+
}
6672

67-
#[cfg(feature = "json")]
68-
formats.insert(FileFormat::Json, vec!["json"]);
73+
pub(crate) fn extensions(&self) -> &'static [&'static str] {
74+
match self {
75+
#[cfg(feature = "toml")]
76+
FileFormat::Toml => &["toml"],
6977

70-
#[cfg(feature = "yaml")]
71-
formats.insert(FileFormat::Yaml, vec!["yaml", "yml"]);
78+
#[cfg(feature = "json")]
79+
FileFormat::Json => &["json"],
7280

73-
#[cfg(feature = "ini")]
74-
formats.insert(FileFormat::Ini, vec!["ini"]);
81+
#[cfg(feature = "yaml")]
82+
FileFormat::Yaml => &["yaml", "yml"],
7583

76-
#[cfg(feature = "ron")]
77-
formats.insert(FileFormat::Ron, vec!["ron"]);
84+
#[cfg(feature = "ini")]
85+
FileFormat::Ini => &["ini"],
7886

79-
#[cfg(feature = "json5")]
80-
formats.insert(FileFormat::Json5, vec!["json5"]);
87+
#[cfg(feature = "ron")]
88+
FileFormat::Ron => &["ron"],
8189

82-
formats
83-
})
84-
}
90+
#[cfg(feature = "json5")]
91+
FileFormat::Json5 => &["json5"],
8592

86-
impl FileFormat {
87-
pub(crate) fn extensions(&self) -> &'static [&'static str] {
88-
// It should not be possible for this to fail
89-
// A FileFormat would need to be declared without being added to the
90-
// all_extensions map.
91-
all_extensions().get(self).unwrap()
93+
#[cfg(all(
94+
not(feature = "toml"),
95+
not(feature = "json"),
96+
not(feature = "yaml"),
97+
not(feature = "ini"),
98+
not(feature = "ron"),
99+
not(feature = "json5"),
100+
))]
101+
_ => unreachable!("No features are enabled, this library won't work without features"),
102+
}
92103
}
93104

94105
pub(crate) fn parse(

src/file/source/file.rs

Lines changed: 23 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,7 @@ use std::fs;
44
use std::io;
55
use std::path::PathBuf;
66

7-
use crate::file::{
8-
format::all_extensions, source::FileSourceResult, FileSource, FileStoredFormat, Format,
9-
};
7+
use crate::file::{source::FileSourceResult, FileFormat, FileSource, FileStoredFormat, Format};
108

119
/// Describes a file sourced from a file
1210
#[derive(Clone, Debug)]
@@ -27,70 +25,61 @@ impl FileSourceFile {
2725
where
2826
F: FileStoredFormat + Format + 'static,
2927
{
30-
let filename = if self.name.is_absolute() {
28+
let path = if self.name.is_absolute() {
3129
self.name.clone()
3230
} else {
3331
env::current_dir()?.as_path().join(&self.name)
3432
};
3533

3634
// First check for an _exact_ match
37-
if filename.is_file() {
38-
return if let Some(format) = format_hint {
39-
Ok((filename, Box::new(format)))
35+
if path.is_file() {
36+
if let Some(format) = format_hint {
37+
return Ok((path, Box::new(format)));
4038
} else {
41-
for (format, extensions) in all_extensions().iter() {
42-
if extensions.contains(
43-
&filename
44-
.extension()
45-
.unwrap_or_default()
46-
.to_string_lossy()
47-
.as_ref(),
48-
) {
49-
return Ok((filename, Box::new(*format)));
39+
let ext = path.extension().unwrap_or_default().to_string_lossy();
40+
for format in FileFormat::all() {
41+
if format.extensions().contains(&ext.as_ref()) {
42+
return Ok((path, Box::new(*format)));
5043
}
5144
}
52-
53-
Err(Box::new(io::Error::new(
45+
return Err(Box::new(io::Error::new(
5446
io::ErrorKind::NotFound,
5547
format!(
56-
"configuration file \"{}\" is not of a registered file format",
57-
filename.to_string_lossy()
48+
"configuration file \"{}\" is not of a supported file format",
49+
path.to_string_lossy()
5850
),
59-
)))
51+
)));
6052
};
6153
}
6254

63-
let mut filename = filename;
55+
let mut path = path;
6456
// Preserve any extension-like text within the provided file stem by appending a fake extension
6557
// which will be replaced by `set_extension()` calls (e.g. `file.local.placeholder` => `file.local.json`)
66-
if filename.extension().is_some() {
67-
filename.as_mut_os_string().push(".placeholder");
58+
if path.extension().is_some() {
59+
path.as_mut_os_string().push(".placeholder");
6860
}
69-
7061
match format_hint {
7162
Some(format) => {
7263
for ext in format.file_extensions() {
73-
filename.set_extension(ext);
64+
path.set_extension(ext);
7465

75-
if filename.is_file() {
76-
return Ok((filename, Box::new(format)));
66+
if path.is_file() {
67+
return Ok((path, Box::new(format)));
7768
}
7869
}
7970
}
80-
8171
None => {
82-
for format in all_extensions().keys() {
72+
for format in FileFormat::all() {
8373
for ext in format.extensions() {
84-
filename.set_extension(ext);
74+
path.set_extension(ext);
8575

86-
if filename.is_file() {
87-
return Ok((filename, Box::new(*format)));
76+
if path.is_file() {
77+
return Ok((path, Box::new(*format)));
8878
}
8979
}
9080
}
9181
}
9282
}
93-
9483
Err(Box::new(io::Error::new(
9584
io::ErrorKind::NotFound,
9685
format!(

0 commit comments

Comments
 (0)