prefer/
lib.rs

1//! # prefer
2//!
3//! A lightweight library for managing application configurations with support for multiple file formats.
4//!
5//! `prefer` helps you manage application configurations while providing users the flexibility
6//! of using whatever configuration format fits their needs.
7//!
8//! ## no_std Support
9//!
10//! This crate supports `no_std` environments with `alloc`. The core types (`ConfigValue`, `FromValue`,
11//! `ValueVisitor`) work without std. Enable the `std` feature for file I/O, async loading, and format parsers.
12//!
13//! ## Features
14//!
15//! - **no_std compatible**: Core types work with just `alloc`
16//! - **Format-agnostic**: Supports JSON, JSON5, YAML, TOML, INI, and XML (with `std`)
17//! - **Automatic discovery**: Searches standard system paths for configuration files (with `std`)
18//! - **Async by design**: Non-blocking operations for file I/O (with `std`)
19//! - **File watching**: Monitor configuration files for changes (with `std`)
20//! - **Dot-notation access**: Access nested values with `"auth.username"`
21//! - **No serde required**: Uses a lightweight `FromValue` trait instead
22//!
23//! ## Examples
24//!
25//! ```no_run
26//! # #[cfg(feature = "std")]
27//! # {
28//! use prefer::load;
29//!
30//! #[tokio::main]
31//! async fn main() -> prefer::Result<()> {
32//!     // Load configuration from any supported format
33//!     let config = load("settings").await?;
34//!
35//!     // Access values using dot notation
36//!     let username: String = config.get("auth.username")?;
37//!     println!("Username: {}", username);
38//!
39//!     Ok(())
40//! }
41//! # }
42//! ```
43
44#![cfg_attr(not(feature = "std"), no_std)]
45
46#[cfg(not(feature = "std"))]
47extern crate alloc;
48
49#[cfg(feature = "std")]
50pub mod builder;
51#[cfg(feature = "std")]
52pub mod config;
53#[cfg(feature = "std")]
54pub mod discovery;
55pub mod error;
56#[cfg(feature = "std")]
57pub mod formats;
58#[cfg(feature = "std")]
59pub mod source;
60pub mod value;
61pub mod visitor;
62#[cfg(feature = "std")]
63pub mod watch;
64
65// Core types (always available)
66pub use error::{Error, Result};
67pub use value::{ConfigValue, FromValue};
68pub use visitor::{SeqAccess, ValueVisitor};
69
70// std-dependent types
71#[cfg(feature = "std")]
72pub use builder::ConfigBuilder;
73#[cfg(feature = "std")]
74pub use config::Config;
75#[cfg(feature = "std")]
76pub use source::{EnvSource, FileSource, LayeredSource, MemorySource, Source};
77
78// Re-export the derive macro when the feature is enabled
79#[cfg(feature = "derive")]
80pub use prefer_derive::FromValue;
81
82/// Load a configuration file by name.
83///
84/// This function searches standard system paths for a configuration file
85/// matching the given name with any supported extension. The first file
86/// found is loaded and parsed according to its format.
87///
88/// # Arguments
89///
90/// * `name` - The base name of the configuration file (without path or extension)
91///
92/// # Returns
93///
94/// A `Config` instance containing the parsed configuration data.
95///
96/// # Examples
97///
98/// ```no_run
99/// # #[cfg(feature = "std")]
100/// # {
101/// use prefer::load;
102///
103/// #[tokio::main]
104/// async fn main() -> prefer::Result<()> {
105///     let config = load("myapp").await?;
106///     let value: String = config.get("some.key")?;
107///     Ok(())
108/// }
109/// # }
110/// ```
111#[cfg(feature = "std")]
112pub async fn load(name: &str) -> Result<Config> {
113    Config::load(name).await
114}
115
116/// Watch a configuration file for changes.
117///
118/// Returns a stream that yields new `Config` instances whenever the
119/// configuration file is modified on disk.
120///
121/// # Arguments
122///
123/// * `name` - The base name of the configuration file (without path or extension)
124///
125/// # Returns
126///
127/// A receiver channel that yields `Config` instances when the file changes.
128///
129/// # Examples
130///
131/// ```no_run
132/// # #[cfg(feature = "std")]
133/// # {
134/// use prefer::watch;
135///
136/// #[tokio::main]
137/// async fn main() -> prefer::Result<()> {
138///     let mut receiver = watch("myapp").await?;
139///
140///     while let Some(config) = receiver.recv().await {
141///         println!("Configuration updated!");
142///         let value: String = config.get("some.key")?;
143///     }
144///
145///     Ok(())
146/// }
147/// # }
148/// ```
149#[cfg(feature = "std")]
150pub async fn watch(name: &str) -> Result<tokio::sync::mpsc::Receiver<Config>> {
151    watch::watch(name).await
152}