config_lib/lib.rs
1//! # config-lib - Multi-Format Configuration Library
2//!
3//! A high-performance configuration management library supporting multiple formats
4//! including CONF, NOML, TOML, and JSON with advanced features like format preservation,
5//! async operations, and schema validation.
6//!
7//! ## Quick Start
8//!
9//! ```rust
10//! use config_lib::Config;
11//!
12//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
13//! // Parse any supported format automatically
14//! let mut config = Config::from_string("port = 8080\nname = \"MyApp\"", None)?;
15//!
16//! // Access values with type safety
17//! let port: i64 = config
18//! .get("port")
19//! .ok_or_else(|| config_lib::Error::key_not_found("port"))?
20//! .as_integer()?;
21//! let name: String = config
22//! .get("name")
23//! .ok_or_else(|| config_lib::Error::key_not_found("name"))?
24//! .as_string()?
25//! .to_owned();
26//!
27//! // Modify and save (preserves format and comments)
28//! config.set("port", 9000)?;
29//! # let _ = (port, name);
30//! # Ok(())
31//! # }
32//! ```
33//!
34//! ## Supported Formats
35//!
36//! - **CONF** - Built-in parser for standard .conf files (default)
37//! - **NOML** - Advanced configuration with dynamic features (feature: `noml`)
38//! - **TOML** - Standard TOML format with format preservation (feature: `toml`)
39//! - **JSON** - JSON format with edit capabilities (feature: `json`)
40//!
41//! ## Features
42//!
43//! - **High Performance** - Zero-copy parsing where possible
44//! - **Format Preservation** - Maintains comments, whitespace, and formatting
45//! - **Async Native** - Full async/await support (feature: `async`)
46//! - **Schema Validation** - Type safety and validation (feature: `schema`)
47//! - **Cross Platform** - Linux, macOS, and Windows support
48//! - **Type Safety** - Rich type system with automatic conversions
49
50// REPS — Rust Efficiency & Performance Standards (project-wide lint discipline).
51// Shipping code MUST satisfy these denies; test code carries narrower
52// allows with `REPS-AUDIT:` justifications where ergonomics outweigh the strict rule.
53#![deny(missing_docs)]
54#![deny(unsafe_op_in_unsafe_fn)]
55#![deny(unused_must_use)]
56#![deny(clippy::unwrap_used)]
57#![deny(clippy::expect_used)]
58#![deny(clippy::todo)]
59#![deny(clippy::unimplemented)]
60#![deny(clippy::print_stdout)]
61#![deny(clippy::print_stderr)]
62#![deny(clippy::dbg_macro)]
63#![deny(clippy::undocumented_unsafe_blocks)]
64#![deny(clippy::missing_safety_doc)]
65#![warn(clippy::pedantic)]
66// REPS-AUDIT: `clippy::pedantic` is a curated lint group, not a hard rule.
67// The following lints are turned back to `allow` because they fire on
68// idioms this crate uses deliberately, or because they trade real
69// readability against pure stylistic preference. The denies above
70// (REPS safety / correctness rules) remain in force.
71//
72// Style / API-shape noise:
73#![allow(clippy::module_name_repetitions)]
74#![allow(clippy::must_use_candidate)]
75#![allow(clippy::return_self_not_must_use)]
76#![allow(clippy::similar_names)]
77#![allow(clippy::wildcard_imports)]
78#![allow(clippy::used_underscore_binding)]
79#![allow(clippy::no_effect_underscore_binding)]
80// Numeric casts at bounded parser/stats boundaries:
81#![allow(clippy::cast_precision_loss)]
82#![allow(clippy::cast_possible_wrap)]
83#![allow(clippy::cast_possible_truncation)]
84#![allow(clippy::cast_sign_loss)]
85// Documentation style preference:
86#![allow(clippy::doc_markdown)]
87#![allow(clippy::missing_errors_doc)]
88#![allow(clippy::missing_panics_doc)]
89// Refactor suggestions deferred to a dedicated cleanup phase
90// (see `.dev/ROADMAP.md` post-1.0 backlog):
91#![allow(clippy::unused_self)]
92#![allow(clippy::self_only_used_in_recursion)]
93#![allow(clippy::unnecessary_wraps)]
94#![allow(clippy::needless_pass_by_value)]
95#![allow(clippy::redundant_closure_for_method_calls)]
96#![allow(clippy::map_unwrap_or)]
97#![allow(clippy::manual_let_else)]
98#![allow(clippy::match_same_arms)]
99#![allow(clippy::single_match_else)]
100#![allow(clippy::inline_always)]
101#![allow(clippy::format_push_string)]
102#![allow(clippy::case_sensitive_file_extension_comparisons)]
103#![allow(clippy::single_char_pattern)]
104#![allow(clippy::unnecessary_literal_bound)]
105#![allow(clippy::if_not_else)]
106#![allow(clippy::struct_excessive_bools)]
107#![allow(clippy::too_many_lines)]
108#![allow(clippy::large_enum_variant)]
109#![allow(clippy::missing_const_for_fn)]
110#![allow(clippy::needless_for_each)]
111#![allow(clippy::implicit_hasher)]
112#![allow(clippy::ignored_unit_patterns)]
113// REPS-AUDIT: test modules use `.unwrap()` / `.expect()` / `panic!` for terse
114// failure assertions, may emit `println!` / `eprintln!` for debug context,
115// and use raw-string-with-hashes / direct float `==` / unseparated literals
116// where the test input is more readable left as written. Allowed under
117// `cfg(test)` only; never reachable in shipped binaries.
118#![cfg_attr(
119 test,
120 allow(
121 clippy::unwrap_used,
122 clippy::expect_used,
123 clippy::panic,
124 clippy::print_stdout,
125 clippy::print_stderr,
126 clippy::needless_raw_string_hashes,
127 clippy::float_cmp,
128 clippy::unreadable_literal,
129 clippy::manual_assert,
130 clippy::ignore_without_reason,
131 )
132)]
133
134pub mod config;
135/// Enterprise-grade configuration management with advanced caching, performance optimizations,
136/// and multi-instance support. Provides thread-safe caching with `Arc<RwLock>` for high-concurrency
137/// environments and sub-50ns access times for cached values.
138pub mod enterprise; // Enterprise API with caching and performance
139pub mod error;
140pub mod parsers;
141pub mod value;
142
143#[cfg(feature = "schema")]
144pub mod schema;
145
146#[cfg(feature = "validation")]
147pub mod validation;
148
149/// Hot reloading system for zero-downtime configuration updates
150pub mod hot_reload;
151
152/// Comprehensive audit logging system for configuration operations
153pub mod audit;
154
155/// Environment variable override system for smart configuration overrides
156#[cfg(feature = "env-override")]
157pub mod env_override;
158
159// Re-export main types for convenience
160pub use config::{CacheStats, Config, ConfigBuilder, ConfigOptions, ConfigValue};
161#[allow(deprecated)]
162// see `enterprise.rs` — the items themselves carry the deprecation notices
163pub use enterprise::{ConfigManager, EnterpriseConfig};
164pub use error::{Error, Result};
165pub use value::Value;
166
167#[cfg(feature = "schema")]
168pub use schema::{Schema, SchemaBuilder};
169
170#[cfg(feature = "validation")]
171pub use validation::{
172 ValidationError, ValidationResult, ValidationRule, ValidationRuleSet, ValidationSeverity,
173};
174
175use std::path::Path;
176
177/// Parse configuration from a string with optional format hint
178///
179/// This is the primary entry point for parsing configuration data from strings.
180/// Automatically detects format if not specified.
181///
182/// # Arguments
183///
184/// * `source` - The configuration data as a string
185/// * `format` - Optional format hint ("conf", "toml", "json", "noml")
186///
187/// # Returns
188///
189/// Returns a [`Value`] containing the parsed configuration data.
190///
191/// # Errors
192///
193/// Returns an error if:
194/// - The input format is unknown or unsupported
195/// - The input contains syntax errors
196/// - Required features are not enabled for the detected format
197///
198/// # Examples
199///
200/// ```rust
201/// use config_lib::parse;
202///
203/// let config = parse("port = 8080\nname = \"MyApp\"", Some("conf"))?;
204/// let port = config
205/// .get("port")
206/// .ok_or_else(|| config_lib::Error::key_not_found("port"))?
207/// .as_integer()?;
208/// # let _ = port;
209/// # Ok::<(), config_lib::Error>(())
210/// ```
211pub fn parse(source: &str, format: Option<&str>) -> Result<Value> {
212 parsers::parse_string(source, format)
213}
214
215/// Parse configuration from a file, auto-detecting format from extension
216///
217/// Reads a configuration file from disk and automatically detects the format
218/// based on the file extension (.conf, .toml, .json, .noml).
219///
220/// # Arguments
221///
222/// * `path` - Path to the configuration file
223///
224/// # Returns
225///
226/// Returns a [`Value`] containing the parsed configuration data.
227///
228/// # Errors
229///
230/// Returns an error if:
231/// - The file cannot be read (I/O error)
232/// - The file format cannot be detected
233/// - The file contains syntax errors
234/// - Required features are not enabled for the detected format
235///
236/// # Examples
237///
238/// ```rust,no_run
239/// use config_lib::parse_file;
240///
241/// let config = parse_file("app.conf")?;
242/// let port = config
243/// .get("server.port")
244/// .ok_or_else(|| config_lib::Error::key_not_found("server.port"))?
245/// .as_integer()?;
246/// # let _ = port;
247/// # Ok::<(), config_lib::Error>(())
248/// ```
249pub fn parse_file<P: AsRef<Path>>(path: P) -> Result<Value> {
250 parsers::parse_file(path)
251}
252
253/// Validate configuration against a schema
254///
255/// Performs comprehensive validation of configuration data against a provided
256/// schema definition.
257///
258/// # Arguments
259///
260/// * `config` - Configuration value to validate
261/// * `schema` - Schema definition for validation
262///
263/// # Returns
264///
265/// Returns `Ok(())` if validation passes, or an error describing the issue.
266///
267/// # Examples
268///
269/// ```rust
270/// # #[cfg(feature = "schema")]
271/// # {
272/// use config_lib::{parse, SchemaBuilder};
273///
274/// let config = parse(r#"
275/// name = "my-app"
276/// port = 8080
277/// "#, None)?;
278///
279/// let schema = SchemaBuilder::new()
280/// .require_string("name")
281/// .require_integer("port")
282/// .build();
283///
284/// config_lib::validate(&config, &schema)?;
285/// # }
286///
287/// # Ok::<(), config_lib::Error>(())
288/// ```
289#[cfg(feature = "schema")]
290pub fn validate(config: &Value, schema: &Schema) -> Result<()> {
291 schema.validate(config)
292}
293
294/// Async version of parse_file
295///
296/// Available when the `async` feature is enabled.
297#[cfg(feature = "async")]
298pub async fn parse_file_async<P: AsRef<Path>>(path: P) -> Result<Value> {
299 parsers::parse_file_async(path).await
300}