I want to load configuration for my project from a file and have the option to use both JSON and YAML formats. I would like to get feedback and suggestions on a way to get the extension of path
and use match
to determine the file format and initialize the program accordingly.
A Startup::from_file
method works like this, loading the contents of json file into a struct
:
impl Startup {
pub fn from_file(path: impl AsRef<Path>) -> Result<Self, StartupError> {
Self::from_file_setup(serde_json::from_str::<StartupInputs>(
&std::fs::read_to_string(path.as_ref())?
)?)
You can replace serde_json
with serde_yaml
but I can't see a smooth way to get the extension, check it's lowercase (if that's important?) and then match it.
The code below is what I have so far, which compiles:
impl Startup {
pub fn from_file(path: impl AsRef<Path>) -> Result<Self, StartupError> {
match path
.as_ref()
.extension()
.ok_or(StartupError::ExtensionNotReadable)?
.to_str()
{
Some("yaml") => Self::from_file_model(serde_yaml::from_str::<StartupInputs>(
&std::fs::read_to_string(path.as_ref())?,
)?),
Some("json") => Self::from_file_model(serde_json::from_str::<StartupInputs>(
&std::fs::read_to_string(path.as_ref())?,
)?),
Some(&_) => Err(StartupError::ExtensionInvalid),
None => Err(StartupError::ExtensionNotReadable),
}
}
Edit:
If the path is “something.json” and I try to parse a json file through serde_yaml::read_to_string
that doesn’t compile and vice versa. Assuming sometimes I’m going to get yaml files and sometimes json files, I want either to work upon startup.
Edit 2:
Thanks to everyone who responded. This is what I settled on:
impl Startup {
fn from_json(file: &str) -> Result<Self, StartupError> {
match serde_json::from_str::<StartupInputs>(file) {
Err(source) => Err(StartupError::InvalidJson { source }),
Ok(model) => Self::from_model(model),
}
}
fn from_yaml(file: &str) -> Result<Self, StartupError> {
match serde_yaml::from_str::<StartupInputs>(file) {
Err(source) => Err(StartupError::InvalidYaml { source }),
Ok(model) => Self::from_model(model),
}
}
pub fn from_file(path: impl AsRef<Path>) -> Result<Self, StartupError> {
let path = path.as_ref();
let file: String = std::fs::read_to_string(&path)?;
match path.extension().and_then(|s| s.to_str()) {
Some("json") => Self::from_json(&file),
_ => Self::from_yaml(&file),
}
}