
The Singleton Pattern is a creational design pattern that ensures a class has only one instance throughout the application’s lifecycle and provides a global access point to it.
In other words:
Only one object exists, and it is shared across the entire program.
Below is a practical Singleton implementation for managing application configuration in Rust using OnceLock for thread-safe, one-time initialization.
rust
CopyEdit
use crate::errors::ServiceError;
use std::sync::OnceLock;
pub struct Config {
pub database_url: String,
pub rocksdb_path: String,
pub rocksdb_buffer_size: usize,
pub gmail_username: String,
pub gmail_app_password: String,
pub jwt_secret: String,
pub architector_server_url: String,
}
impl Config {
fn new() -> Result<Config, ServiceError> {
dotenv::dotenv().ok();
Ok(Config {
database_url: std::env::var("DATABASE_URL").unwrap(),
rocksdb_path: std::env::var("ROCKSDB_PATH")
.unwrap_or_else(|_| "./rocksdb_data".to_string()),
rocksdb_buffer_size: std::env::var("ROCKSDB_BUFFER_SIZE")
.unwrap_or_else(|_| (1024 * 1024).to_string())
.parse()
.unwrap(),
gmail_username: std::env::var("GMAIL_USERNAME").unwrap(),
gmail_app_password: std::env::var("GMAIL_APP_PASSWORD").unwrap(),
jwt_secret: std::env::var("JWT_SECRET")
.unwrap_or_else(|_| "your-secret-key".to_string()),
architector_server_url: std::env::var("ARCHITECTOR_SERVER_URL")
.unwrap_or_else(|_| "http://localhost:8000".to_string()),
})
}
}
// Singleton accessor
pub fn get_config() -> &'static Config {
static CONFIG: OnceLock<Config> = OnceLock::new();
CONFIG.get_or_init(|| Config::new().unwrap())
}
pub struct OnceLock<T> {
once: Once,
value: UnsafeCell<MaybeUninit<T>>,
_marker: PhantomData<T>,
}
OnceLock<T> is a thread-safe cell for one-time initialization. The first call to get_or_init() runs the initializer exactly once, and all later calls return the same reference without locking. It’s ideal for implementing global Singletons in Rust.
get_config() triggers Config::new().fn main() {
let config = get_config();
println!("DB URL: {}", config.database_url);
}
Here, config is always the same instance across the entire program.
OnceLock guarantees safe initialization in concurrent contexts.Use it when:
Avoid it when:
The Singleton Pattern is a powerful yet double-edged tool.
In Rust, OnceLock makes it possible to implement this pattern elegantly and safely. By sharing a single instance across the application, Singleton ensures consistent behavior, efficient resource usage, and simplified code management.