use singleton_registry::define_registry;
use std::sync::Arc;
use std::thread;
use std::time::Duration;
define_registry!(config);
#[derive(Debug, Clone)]
struct AppSettings {
api_endpoint: String,
timeout_ms: u64,
version: u32,
}
impl AppSettings {
fn describe(&self) -> String {
format!(
"v{} -> {} (timeout: {}ms)",
self.version, self.api_endpoint, self.timeout_ms
)
}
}
fn main() {
println!("=== singleton-registry: Singleton Replacement ===\n");
println!("1. Registering initial configuration...");
let initial_settings = AppSettings {
api_endpoint: "https://api.v1.example.com".to_string(),
timeout_ms: 5000,
version: 1,
};
config::register(initial_settings);
let settings_v1: Arc<AppSettings> = config::get().unwrap();
println!(" Initial: {}", settings_v1.describe());
println!(" Arc strong count: {}", Arc::strong_count(&settings_v1));
println!("\n2. Holding reference to current configuration...");
let held_reference: Arc<AppSettings> = config::get().unwrap();
println!(" Held reference version: {}", held_reference.version);
println!(
" Arc strong count (before replacement): {}",
Arc::strong_count(&held_reference)
);
println!("\n3. Replacing singleton with new configuration...");
let updated_settings = AppSettings {
api_endpoint: "https://api.v2.example.com".to_string(),
timeout_ms: 10000,
version: 2,
};
config::register(updated_settings);
println!(" Replacement complete!");
println!("\n4. Verifying old reference still works...");
println!(" Old reference endpoint: {}", held_reference.api_endpoint);
println!(" Old reference version: {}", held_reference.version);
println!(
" Old reference Arc strong count: {}",
Arc::strong_count(&held_reference)
);
println!("\n5. New lookups return the replacement...");
let settings_v2: Arc<AppSettings> = config::get().unwrap();
println!(" New lookup endpoint: {}", settings_v2.api_endpoint);
println!(" New lookup version: {}", settings_v2.version);
println!("\n6. Comparing references...");
println!(
" Old ptr: {:p}, New ptr: {:p}",
Arc::as_ptr(&held_reference),
Arc::as_ptr(&settings_v2)
);
println!(
" Same Arc? {}",
Arc::ptr_eq(&held_reference, &settings_v2)
);
println!("\n7. Demonstrating thread-safe concurrent access...\n");
let reader_handle = {
let ref_for_thread: Arc<AppSettings> = config::get().unwrap();
thread::spawn(move || {
println!(
" [Reader Thread] Got version {} before replacement starts",
ref_for_thread.version
);
thread::sleep(Duration::from_millis(100));
println!(
" [Reader Thread] Still using version {} (unchanged)",
ref_for_thread.version
);
ref_for_thread.version
})
};
thread::sleep(Duration::from_millis(10));
println!(" [Main Thread] Replacing to version 3...");
config::register(AppSettings {
api_endpoint: "https://api.v3.example.com".to_string(),
timeout_ms: 15000,
version: 3,
});
println!(" [Main Thread] Replacement complete");
let settings_v3: Arc<AppSettings> = config::get().unwrap();
println!(" [Main Thread] Current version: {}", settings_v3.version);
let reader_saw_version = reader_handle.join().unwrap();
println!(
"\n Reader thread safely used version {} throughout",
reader_saw_version
);
println!("\n=== Example Complete ===");
println!("Key takeaways:");
println!(" - Replacement updates the registry atomically");
println!(" - Existing Arc<T> references remain valid (reference counting)");
println!(" - In-flight operations complete with their original reference");
println!(" - New lookups get the latest registered singleton");
println!(" - Thread-safe: no data races, no undefined behavior");
}