111 lines
3.1 KiB
Rust
111 lines
3.1 KiB
Rust
use std::sync::{Arc, Mutex, OnceLock};
|
|
|
|
// Thread-safe singleton using OnceLock (stable since Rust 1.70)
|
|
pub struct GlobalSingleton {
|
|
data: String,
|
|
counter: u32,
|
|
}
|
|
|
|
impl GlobalSingleton {
|
|
// Private constructor
|
|
fn new() -> Self {
|
|
Self {
|
|
data: String::from("Singleton initialized"),
|
|
counter: 0,
|
|
}
|
|
}
|
|
|
|
// Get the singleton instance
|
|
pub fn instance() -> Arc<Mutex<GlobalSingleton>> {
|
|
static INSTANCE: OnceLock<Arc<Mutex<GlobalSingleton>>> = OnceLock::new();
|
|
|
|
INSTANCE.get_or_init(|| {
|
|
Arc::new(Mutex::new(GlobalSingleton::new()))
|
|
}).clone()
|
|
}
|
|
|
|
// Non-static methods that operate on the singleton instance
|
|
pub fn get_data(&self) -> &str {
|
|
&self.data
|
|
}
|
|
|
|
pub fn set_data(&mut self, new_data: String) {
|
|
self.data = new_data;
|
|
}
|
|
|
|
pub fn increment_counter(&mut self) {
|
|
self.counter += 1;
|
|
}
|
|
|
|
pub fn get_counter(&self) -> u32 {
|
|
self.counter
|
|
}
|
|
}
|
|
|
|
// Alternative implementation using std::sync::LazyLock (stable since Rust 1.80)
|
|
// This is the most modern and clean approach
|
|
use std::sync::LazyLock;
|
|
|
|
static LAZY_SINGLETON: LazyLock<Arc<Mutex<GlobalSingleton>>> = LazyLock::new(|| {
|
|
Arc::new(Mutex::new(GlobalSingleton::new()))
|
|
});
|
|
|
|
impl GlobalSingleton {
|
|
// Alternative method using LazyLock
|
|
pub fn lazy_instance() -> Arc<Mutex<GlobalSingleton>> {
|
|
LAZY_SINGLETON.clone()
|
|
}
|
|
}
|
|
|
|
fn main() {
|
|
// Usage example with OnceLock
|
|
{
|
|
let singleton = GlobalSingleton::instance();
|
|
let mut instance = singleton.lock().unwrap();
|
|
println!("Initial data: {}", instance.get_data());
|
|
instance.increment_counter();
|
|
instance.set_data("Modified data".to_string());
|
|
println!("Counter: {}", instance.get_counter());
|
|
}
|
|
|
|
// Access from another scope - same instance
|
|
{
|
|
let singleton = GlobalSingleton::instance();
|
|
let instance = singleton.lock().unwrap();
|
|
println!("Data from another scope: {}", instance.get_data());
|
|
println!("Counter from another scope: {}", instance.get_counter());
|
|
}
|
|
|
|
// Demonstrate thread safety
|
|
use std::thread;
|
|
|
|
let handles: Vec<_> = (0..3)
|
|
.map(|i| {
|
|
thread::spawn(move || {
|
|
let singleton = GlobalSingleton::instance();
|
|
let mut instance = singleton.lock().unwrap();
|
|
instance.increment_counter();
|
|
println!("Thread {} incremented counter to: {}", i, instance.get_counter());
|
|
})
|
|
})
|
|
.collect();
|
|
|
|
for handle in handles {
|
|
handle.join().unwrap();
|
|
}
|
|
|
|
// Final state
|
|
let singleton = GlobalSingleton::instance();
|
|
let instance = singleton.lock().unwrap();
|
|
println!("Final counter value: {}", instance.get_counter());
|
|
|
|
// Demonstrate LazyLock alternative
|
|
println!("\n--- Using LazyLock alternative ---");
|
|
{
|
|
let singleton = GlobalSingleton::lazy_instance();
|
|
let mut instance = singleton.lock().unwrap();
|
|
instance.set_data("LazyLock data".to_string());
|
|
println!("LazyLock data: {}", instance.get_data());
|
|
}
|
|
}
|