| Crates.io | prism3-config |
| lib.rs | prism3-config |
| version | 0.1.1 |
| created_at | 2025-10-14 06:43:51.703636+00 |
| updated_at | 2025-10-14 07:13:15.51934+00 |
| description | Powerful type-safe configuration management with multi-value properties, variable substitution, and rich data type support |
| homepage | https://github.com/3-prism/prism3-rust-config |
| repository | https://github.com/3-prism/prism3-rust-config |
| max_upload_size | |
| id | 1881758 |
| size | 235,787 |
A powerful, type-safe configuration management system for Rust, providing flexible configuration management with support for multiple data types, variable substitution, and multi-value properties.
get<T>() and set<T>() generic methods with full type inference support${var_name} style variable substitution from config or environmentAdd this to your Cargo.toml:
[dependencies]
prism3-config = "0.1"
use prism3_config::Config;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut config = Config::new();
// Set configuration values
config.set("port", 8080)?;
config.set("host", "localhost")?;
config.set("debug", true)?;
// Read configuration values (with type inference)
let port: i32 = config.get("port")?;
let host: String = config.get("host")?;
let debug: bool = config.get("debug")?;
// Use turbofish syntax
let port = config.get::<i32>("port")?;
// Use default values
let timeout: u64 = config.get_or("timeout", 30);
println!("Server running on {}:{}", host, port);
Ok(())
}
The Config struct is the central configuration manager that stores and manages all configuration properties.
let mut config = Config::new();
config.set("database.host", "localhost")?;
config.set("database.port", 5432)?;
Each configuration item is represented by a Property that contains:
A type-safe container that can hold multiple values of the same data type.
use prism3_config::Config;
let mut config = Config::new();
// Set various types
config.set("port", 8080)?;
config.set("host", "localhost")?;
config.set("debug", true)?;
config.set("timeout", 30.5)?;
// Get values with type inference
let port: i32 = config.get("port")?;
let host: String = config.get("host")?;
let debug: bool = config.get("debug")?;
// Set multiple values
config.set("ports", vec![8080, 8081, 8082])?;
// Get all values
let ports: Vec<i32> = config.get_list("ports")?;
// Add values incrementally
config.set("server", "server1")?;
config.add("server", "server2")?;
config.add("server", "server3")?;
let servers: Vec<String> = config.get_list("server")?;
config.set("host", "localhost")?;
config.set("port", "8080")?;
config.set("url", "http://${host}:${port}/api")?;
// Variables are automatically substituted
let url = config.get_string("url")?;
// Result: "http://localhost:8080/api"
// Environment variables are also supported
std::env::set_var("APP_ENV", "production");
config.set("env", "${APP_ENV}")?;
let env = config.get_string("env")?;
// Result: "production"
#[derive(Debug)]
struct DatabaseConfig {
host: String,
port: i32,
username: String,
password: String,
}
let mut config = Config::new();
config.set("db.host", "localhost")?;
config.set("db.port", 5432)?;
config.set("db.username", "admin")?;
config.set("db.password", "secret")?;
let db_config = DatabaseConfig {
host: config.get("db.host")?,
port: config.get("db.port")?,
username: config.get("db.username")?,
password: config.get("db.password")?,
};
use prism3_config::{Configurable, Configured};
// Use the Configured base class
let mut configured = Configured::new();
configured.config_mut().set("port", 3000)?;
// Custom configurable object
struct Application {
configured: Configured,
}
impl Application {
fn new() -> Self {
Self {
configured: Configured::new(),
}
}
fn config(&self) -> &Config {
self.configured.config()
}
fn config_mut(&mut self) -> &mut Config {
self.configured.config_mut()
}
}
let mut app = Application::new();
app.config_mut().set("port", 3000)?;
| Rust Type | Description | Example |
|---|---|---|
bool |
Boolean value | true, false |
char |
Character | 'a', '中' |
i8, i16, i32, i64, i128 |
Signed integers | 42, -100 |
u8, u16, u32, u64, u128 |
Unsigned integers | 255, 1000 |
f32, f64 |
Floating point | 3.14, 2.718 |
String |
String | "hello", "世界" |
Vec<u8> |
Byte array | [1, 2, 3, 4] |
chrono::NaiveDate |
Date | 2025-01-01 |
chrono::NaiveTime |
Time | 12:30:45 |
chrono::NaiveDateTime |
Date and time | 2025-01-01 12:30:45 |
chrono::DateTime<Utc> |
Timestamped datetime | 2025-01-01T12:30:45Z |
To support custom types in the configuration system, you need to implement the necessary traits from prism3_value. The configuration system uses the MultiValues infrastructure for type-safe storage and retrieval.
Here's an example of how to work with custom types:
use prism3_config::Config;
// Define your custom type
#[derive(Debug, Clone, PartialEq)]
struct Port(u16);
// You can use the configuration system with types that can be converted to/from primitive types
impl Port {
fn new(value: u16) -> Result<Self, String> {
if value < 1024 {
Err("Port must be >= 1024".to_string())
} else {
Ok(Port(value))
}
}
fn value(&self) -> u16 {
self.0
}
}
// Usage with the configuration system
let mut config = Config::new();
// Store the port as a primitive type
config.set("port", 8080u16)?;
// Retrieve and wrap in custom type
let port_value: u16 = config.get("port")?;
let port = Port::new(port_value).map_err(|e| ConfigError::ConversionError(e))?;
// Or use get_or with validation
let port = Port::new(config.get_or("port", 8080u16))
.map_err(|e| ConfigError::ConversionError(e))?;
For more advanced type conversions, you can implement the traits from prism3_value (MultiValuesFirstGetter, MultiValuesSetter, etc.). See the prism3_value documentation for details on implementing these traits for custom types.
We use a pure generic approach (only providing get<T>(), set<T>(), get_or<T>() core methods) instead of type-specific methods (like get_i32(), get_string(), etc.) because:
// 1. Variable type annotation (recommended, most clear)
let port: i32 = config.get("port")?;
// 2. Turbofish syntax (use when needed)
let port = config.get::<i32>("port")?;
// 3. Context inference (most concise)
struct Server {
port: i32,
}
let server = Server {
port: config.get("port")?, // Inferred from field type
};
The configuration system uses ConfigResult<T> for error handling:
pub enum ConfigError {
PropertyNotFound(String), // Property does not exist
PropertyHasNoValue(String), // Property has no value
TypeMismatch { expected: DataType, actual: DataType }, // Type mismatch
ConversionError(String), // Type conversion failed
IndexOutOfBounds { index: usize, len: usize }, // Index out of bounds
SubstitutionError(String), // Variable substitution failed
SubstitutionDepthExceeded(usize), // Variable substitution depth exceeded
MergeError(String), // Configuration merge failed
PropertyIsFinal(String), // Property is final and cannot be overwritten
IoError(std::io::Error), // IO error
ParseError(String), // Parse error
Other(String), // Other errors
}
OnceLock to cache regex patterns, avoiding repeated compilationHashMap with O(1) lookup time complexityArcRun the test suite:
cargo test
Run with code coverage:
./coverage.sh
For detailed API documentation, visit docs.rs/prism3-config.
For internal design documentation (Chinese), see src/README.md.
prism3-core - Core utilities and data type definitionsprism3-value - Value handling frameworkserde - Serialization frameworkchrono - Date and time handlingregex - Regular expression supportSyncConfigContributions are welcome! Please feel free to submit a Pull Request.
Copyright (c) 2025 3-Prism Co. Ltd. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
See LICENSE for the full license text.
Hu Haixing - 3-Prism Co. Ltd.
For more information about the Prism3 ecosystem, visit our GitHub homepage.