diff --git a/Cargo.lock b/Cargo.lock
index ece7313..7e53d46 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -244,6 +244,7 @@ dependencies = [
"rust_decimal",
"secrecy",
"serde",
+ "serde_ini",
"serde_json",
"serde_with",
"signal-hook",
@@ -1101,6 +1102,12 @@ dependencies = [
"bytecheck",
]
+[[package]]
+name = "result"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "194d8e591e405d1eecf28819740abed6d719d1a2db87fc0bcdedee9a26d55560"
+
[[package]]
name = "rkyv"
version = "0.7.46"
@@ -1282,6 +1289,17 @@ dependencies = [
"syn 2.0.117",
]
+[[package]]
+name = "serde_ini"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "eb236687e2bb073a7521c021949be944641e671b8505a94069ca37b656c81139"
+dependencies = [
+ "result",
+ "serde",
+ "void",
+]
+
[[package]]
name = "serde_json"
version = "1.0.149"
@@ -1709,6 +1727,12 @@ version = "0.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
+[[package]]
+name = "void"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
+
[[package]]
name = "wasi"
version = "0.11.1+wasi-snapshot-preview1"
diff --git a/confik/Cargo.toml b/confik/Cargo.toml
index ebf2d2e..6d079fd 100644
--- a/confik/Cargo.toml
+++ b/confik/Cargo.toml
@@ -27,6 +27,7 @@ default = ["env", "toml"]
env = ["dep:envious"]
json = ["dep:serde_json"]
ron-0_12 = ["dep:ron-0_12"]
+serde_ini-0_2 = ["dep:serde_ini-0_2"]
toml = ["dep:toml"]
yaml_serde-0_10 = ["dep:yaml_serde-0_10"]
@@ -63,6 +64,7 @@ thiserror = "2"
# Source types
envious = { version = "0.2", optional = true }
ron-0_12 = { package = "ron", version = "0.12", optional = true }
+serde_ini-0_2 = { package = "serde_ini", version = "0.2", optional = true }
serde_json = { version = "1", optional = true }
toml = { version = "1", optional = true, default-features = false, features = ["parse", "serde"] }
yaml_serde-0_10 = { package = "yaml_serde", version = "0.10", optional = true }
diff --git a/confik/src/lib.md b/confik/src/lib.md
index 8bc24cc..8f1e8f6 100644
--- a/confik/src/lib.md
+++ b/confik/src/lib.md
@@ -123,11 +123,12 @@ When the `tracing` feature is enabled, reload errors in the signal handler will
A [`Source`] is any type that can create [`ConfigurationBuilder`]s. This crate implements the following sources:
- [`EnvSource`]: Loads configuration from environment variables using the [`envious`] crate. Requires the `env` feature. (Enabled by default.)
-- [`FileSource`]: Loads configuration from a file, detecting `.toml`, `.json`, `.ron`, `.yaml`, or `.yml` files based on the file extension. Requires the matching `toml`, `json`, `ron-0_12`, or `yaml_serde-0_10` feature. (`toml` is enabled by default.)
+- [`FileSource`]: Loads configuration from a file, detecting `.toml`, `.json`, `.ron`, `.yaml`, `.yml`, or `.ini` files based on the file extension. Requires the matching `toml`, `json`, `ron-0_12`, `yaml_serde-0_10`, or `serde_ini-0_2` feature. (`toml` is enabled by default.)
- [`TomlSource`]: Loads configuration from a TOML string literal. Requires the `toml` feature. (Enabled by default.)
- [`JsonSource`]: Loads configuration from a JSON string literal. Requires the `json` feature.
- [`RonSource`]: Loads configuration from a RON string literal. Requires the `ron-0_12` feature.
- [`YamlSource`]: Loads configuration from a YAML string literal. Requires the `yaml_serde-0_10` feature.
+- [`IniSource`]: Loads configuration from an INI string literal. Requires the `serde_ini-0_2` feature.
- [`OffsetSource`]: Loads configuration from an inner source that is provided to it, but applied to a particular offset of the root configuration builder.
## Secrets
diff --git a/confik/src/lib.rs b/confik/src/lib.rs
index f2ef195..333be92 100644
--- a/confik/src/lib.rs
+++ b/confik/src/lib.rs
@@ -42,6 +42,8 @@ use self::path::Path;
pub use self::reloading::{ReloadCallback, ReloadableConfig, ReloadingConfig};
#[cfg(feature = "env")]
pub use self::sources::env_source::EnvSource;
+#[cfg(feature = "serde_ini-0_2")]
+pub use self::sources::ini_source::IniSource;
#[cfg(feature = "json")]
pub use self::sources::json_source::JsonSource;
#[cfg(feature = "ron-0_12")]
diff --git a/confik/src/sources/file_source.rs b/confik/src/sources/file_source.rs
index 2354be4..baedf32 100644
--- a/confik/src/sources/file_source.rs
+++ b/confik/src/sources/file_source.rs
@@ -35,6 +35,10 @@ enum FileErrorKind {
#[error(transparent)]
Json(#[from] serde_json::Error),
+ #[cfg(feature = "serde_ini-0_2")]
+ #[error(transparent)]
+ Ini(#[from] serde_ini_0_2::error::Error),
+
#[cfg(feature = "ron-0_12")]
#[error(transparent)]
Ron(#[from] ron_0_12::error::SpannedError),
@@ -57,6 +61,7 @@ impl FileSource {
/// The deserialization method will be determined by the file extension.
///
/// Supported extensions:
+ /// - `ini`
/// - `toml`
/// - `json`
/// - `ron`
@@ -100,6 +105,16 @@ impl FileSource {
}
}
+ Some("ini") => {
+ cfg_if! {
+ if #[cfg(feature = "serde_ini-0_2")] {
+ Ok(serde_ini_0_2::from_str(&contents).map_err(serde_ini_0_2::error::Error::from)?)
+ } else {
+ Err(FileErrorKind::MissingFeatureForExtension("ini"))
+ }
+ }
+ }
+
Some("ron") => {
cfg_if! {
if #[cfg(feature = "ron-0_12")] {
@@ -207,6 +222,29 @@ mod tests {
dir.close().unwrap();
}
+ #[cfg(feature = "serde_ini-0_2")]
+ #[test]
+ fn ini() {
+ let dir = tempfile::TempDir::new().unwrap();
+
+ let ini_path = dir.path().join("config.ini");
+
+ fs::write(&ini_path, "").unwrap();
+ let source = FileSource::new(&ini_path);
+ let err = source.deserialize::