lib_humus_configuration/
io.rs

1// SPDX-FileCopyrightText: 2025 Slatian
2//
3// SPDX-License-Identifier: LGPL-3.0-or-later
4
5use serde::Deserialize;
6
7use std::fs;
8use std::path::Path;
9
10use crate::ConfigFormat;
11use crate::ErrorCause;
12use crate::HumusConfigError;
13use crate::Settings;
14
15/// Read from a given path using the given settings.
16///
17/// File type detection is based on file extension with the preferred type used as fallback for unknown extensions.
18///
19/// No type sniffing or fingerprinting is done.
20pub fn read_from_file<T>(
21	path: impl AsRef<Path>,
22	settings: Settings,
23) -> Result<(T, ConfigFormat), HumusConfigError>
24where
25	T: for<'de> Deserialize<'de>,
26{
27	let text = match fs::read_to_string(&path) {
28		Ok(t) => t,
29		Err(e) => {
30			return Err(HumusConfigError {
31				path: path.as_ref().into(),
32				cause: ErrorCause::FileRead(e),
33			});
34		}
35	};
36
37	let path = path.as_ref();
38
39	let detected_format = ConfigFormat::guess_from_path(path);
40	if let Some(detected_format) = detected_format {
41		if !settings.is_allowed(detected_format) {
42			return Err(HumusConfigError {
43				path: path.into(),
44				cause: ErrorCause::FormatNotAllowed {
45					format: detected_format,
46					prefer: settings.prefer,
47				},
48			});
49		}
50	}
51
52	match detected_format.unwrap_or(settings.prefer) {
53		#[cfg(feature="json")]
54		ConfigFormat::Json => match serde_json::from_str(&text) {
55			Ok(t) => Ok((t, ConfigFormat::Json)),
56			Err(e) => Err(HumusConfigError {
57				path: path.into(),
58				cause: ErrorCause::Json(e),
59			}),
60		},
61		#[cfg(feature="json5")]
62		ConfigFormat::Json5 => match json5::from_str(&text) {
63			Ok(t) => Ok((t, ConfigFormat::Json5)),
64			Err(e) => Err(HumusConfigError {
65				path: path.into(),
66				cause: ErrorCause::Json5(e),
67			}),
68		},
69		#[cfg(feature="toml")]
70		ConfigFormat::Toml => match toml::from_str(&text) {
71			Ok(t) => Ok((t, ConfigFormat::Toml)),
72			Err(e) => Err(HumusConfigError {
73				path: path.into(),
74				cause: ErrorCause::Toml(e),
75			}),
76		},
77	}
78}
79
80#[cfg(feature="json")]
81/// Read from a JSON file at a given path.
82pub fn read_from_json_file<T>(path: impl AsRef<Path>) -> Result<T, HumusConfigError>
83where
84	T: for<'de> Deserialize<'de>,
85{
86	Ok(read_from_file(path, Settings::only_json())?.0)
87}
88
89#[cfg(feature="json5")]
90/// Read from a JSON5 or JSON file at a given path.
91pub fn read_from_json5_file<T>(path: impl AsRef<Path>) -> Result<T, HumusConfigError>
92where
93	T: for<'de> Deserialize<'de>,
94{
95	Ok(read_from_file(path, Settings::only_json5())?.0)
96}
97
98#[cfg(feature="toml")]
99/// Read from a TOML file at a given path.
100pub fn read_from_toml_file<T>(path: impl AsRef<Path>) -> Result<T, HumusConfigError>
101where
102	T: for<'de> Deserialize<'de>,
103{
104	Ok(read_from_file(path, Settings::only_toml())?.0)
105}