### Fast Pointer Access with ArcSwap::load - Rust Source: https://context7.com/vorner/arc-swap/llms.txt Explains how to use the `load` method to get a `Guard` for fast, wait-free access to the stored `Arc`. It emphasizes the importance of short-lived guards for optimal performance and consistent snapshots. ```rust use std::sync::Arc; use arc_swap::ArcSwap; let shared = ArcSwap::from_pointee(42); // Load returns a Guard that derefs to Arc let guard = shared.load(); println!("Value: {}", **guard); // Double deref: Guard -> Arc -> T // Guards are cheap - use one per logical operation for consistency let guard = shared.load(); let a = **guard; let b = **guard; // Same value, consistent snapshot assert_eq!(a, b); // Don't do this - values might differ between loads // let a = **shared.load(); // let b = **shared.load(); // Could be different! ``` -------------------------------- ### Get Owned Arc with ArcSwap::load_full - Rust Source: https://context7.com/vorner/arc-swap/llms.txt Details the `load_full` method, which returns a cloned `Arc` instead of a `Guard`. This is useful when the `Arc` needs to be stored or passed to other functions that require ownership. ```rust use std::sync::Arc; use arc_swap::ArcSwap; let shared = ArcSwap::from_pointee(42); // Get an owned Arc that can be stored or passed around let arc: Arc = shared.load_full(); assert_eq!(42, *arc); assert_eq!(2, Arc::strong_count(&arc)); // One in ArcSwap, one here // Useful when you need to keep the value beyond immediate use fn process_later(data: Arc) { // ... store for later processing } let strings = ArcSwap::from_pointee("important data".to_string()); process_later(strings.load_full()); ``` -------------------------------- ### Abstract Configuration Access with ArcSwap Traits (Rust) Source: https://context7.com/vorner/arc-swap/llms.txt Demonstrates how to use the Access, Constant, Map, and DynAccess traits from arc_swap for abstracting configuration sources. This enables dependency injection and facilitates testing by allowing different configuration providers (real ArcSwap, constant values) to be used interchangeably. DynAccess provides type-erased access to configuration values. ```rust use std::sync::Arc; use arc_swap::ArcSwap; use arc_swap::access::{Access, Constant, Map, DynAccess}; #[derive(Debug, Clone)] struct ServiceConfig { timeout_ms: u64, retries: u32, } // Generic function accepting any config source fn create_service>(config: A) -> String where A::Guard: std::ops::Deref, { let cfg = config.load(); format!("Service with {}ms timeout, {} retries", cfg.timeout_ms, cfg.retries) } // Use with real ArcSwap in production let live_config = Arc::new(ArcSwap::from_pointee(ServiceConfig { timeout_ms: 5000, retries: 3, })); let result = create_service(Map::new(live_config, |c: &ServiceConfig| c)); // Use with Constant in tests let test_config = Constant(ServiceConfig { timeout_ms: 100, retries: 1 }); let test_result = create_service(test_config); // Type-erased access with DynAccess fn use_dynamic_config(config: Box>) { println!("Value: {}", *config.load()); } use_dynamic_config(Box::new(Constant(42u64))); ``` -------------------------------- ### Rust Thread-Safe Configuration with ArcSwap Source: https://context7.com/vorner/arc-swap/llms.txt This Rust code demonstrates a thread-safe configuration pattern using `ArcSwap`. It initializes a configuration struct wrapped in `Arc>`, spawns worker threads that read the configuration, and a separate thread that updates the configuration. Workers can access the latest configuration atomically without locks. ```rust use std::sync::Arc; use std::sync::atomic::{AtomicBool, Ordering}; use std::thread; use std::time::Duration; use arc_swap::ArcSwap; #[derive(Debug)] struct Config { feature_enabled: bool, max_items: usize, api_endpoint: String, } fn main() { // Shared configuration wrapped in Arc> let config = Arc::new(ArcSwap::from_pointee(Config { feature_enabled: false, max_items: 100, api_endpoint: "https://api.example.com".to_string(), })); let running = Arc::new(AtomicBool::new(true)); let mut handles = vec![]; // Spawn worker threads that read config for id in 0..4 { let config = Arc::clone(&config); let running = Arc::clone(&running); handles.push(thread::spawn(move || { while running.load(Ordering::Relaxed) { let cfg = config.load(); if cfg.feature_enabled { println!("Worker {}: Processing up to {} items", id, cfg.max_items); } thread::sleep(Duration::from_millis(100)); } })); } // Config updater thread let config_updater = { let config = Arc::clone(&config); thread::spawn(move || { thread::sleep(Duration::from_millis(200)); // Push new config - all workers will see it on next load config.store(Arc::new(Config { feature_enabled: true, max_items: 500, api_endpoint: "https://api-v2.example.com".to_string(), })); println!("Config updated!"); }) }; config_updater.join().unwrap(); thread::sleep(Duration::from_millis(300)); running.store(false, Ordering::Relaxed); for h in handles { h.join().unwrap(); } } ``` -------------------------------- ### Projecting Configuration Substructures with Map (Rust) Source: https://context7.com/vorner/arc-swap/llms.txt Illustrates the use of the `Map` access trait to provide components with access only to the specific configuration sections they require. This is achieved by mapping a larger configuration structure to a smaller, relevant substructure, promoting modularity and reducing the scope of configuration access. ```rust use std::sync::Arc; use arc_swap::ArcSwap; use arc_swap::access::{Access, Map, DynAccess}; #[derive(Default)] struct FullConfig { server: ServerConfig, database: DatabaseConfig, logging: LogConfig, } #[derive(Default)] struct ServerConfig { port: u16, host: String } #[derive(Default)] struct DatabaseConfig { url: String } #[derive(Default)] struct LogConfig { level: String } let config = Arc::new(ArcSwap::from_pointee(FullConfig::default())); // Each component gets access to only its config section struct Server { config: Box>, } struct Database { config: Box>, } let server = Server { config: Box::new(Map::new(Arc::clone(&config), |c: &FullConfig| &c.server)), }; let database = Database { config: Box::new(Map::new(Arc::clone(&config), |c: &FullConfig| &c.database)), }; // Update entire config - all components see their portion updated config.store(Arc::new(FullConfig { server: ServerConfig { port: 8080, host: "0.0.0.0".to_string() }, database: DatabaseConfig { url: "postgres://db".to_string() }, logging: LogConfig { level: "debug".to_string() }, })); ``` -------------------------------- ### Create and Store ArcSwap - Rust Source: https://context7.com/vorner/arc-swap/llms.txt Demonstrates the creation of ArcSwap instances from direct values or existing Arcs. It also shows default construction for types implementing the Default trait. ```rust use std::sync::Arc; use arc_swap::ArcSwap; // Create from a value directly (wraps in Arc internally) let config = ArcSwap::from_pointee(42); assert_eq!(42, **config.load()); // Create from an existing Arc let arc = Arc::new("Hello, World!"); let shared = ArcSwap::from(arc); assert_eq!("Hello, World!", **shared.load()); // Default construction for Default types let default_swap: ArcSwap = ArcSwap::default(); assert_eq!("", **default_swap.load()); ``` -------------------------------- ### Exchange Values with ArcSwap::swap - Rust Source: https://context7.com/vorner/arc-swap/llms.txt Demonstrates the `swap` method, which atomically exchanges the stored value and returns the previous one. This is useful for updating the value while also needing to access the old state. ```rust use std::sync::Arc; use arc_swap::ArcSwap; let counter = ArcSwap::from_pointee(0); // Swap returns the old value let old = counter.swap(Arc::new(42)); assert_eq!(0, *old); assert_eq!(42, **counter.load()); // Useful for implementing state transitions let state = ArcSwap::from_pointee("idle"); let previous = state.swap(Arc::new("running")); println!("Transitioned from '{}' to 'running'", *previous); ``` -------------------------------- ### Weak Pointer Storage with ArcSwapWeak (Rust) Source: https://context7.com/vorner/arc-swap/llms.txt Demonstrates the usage of `ArcSwapWeak` for storing weak pointers to data managed by `ArcSwap`. This feature, enabled by the `weak` feature flag, ensures that `ArcSwapWeak` does not prevent the underlying data from being deallocated if all strong references are dropped. The `load_full()` method returns a `Weak` pointer that must be `upgrade()`d to access the data. ```rust // Enable with: arc-swap = { version = "1.8", features = ["weak"] } use std::sync::{Arc, Weak}; use arc_swap::ArcSwapWeak; let data = Arc::new("Important data"); let shared = ArcSwapWeak::new(Arc::downgrade(&data)); // Load returns Weak, must upgrade to access let weak = shared.load_full(); assert_eq!("Important data", *weak.upgrade().unwrap()); // When strong references are dropped, weak becomes invalid drop(data); let weak = shared.load_full(); assert!(weak.upgrade().is_none()); // Can store empty weak shared.store(Weak::new()); ``` -------------------------------- ### Cache::map - Projected Cache Views Source: https://context7.com/vorner/arc-swap/llms.txt Cache::map allows the creation of projected views into cached data structures. This is useful for isolating components to only access the specific parts of the data they need, enhancing modularity and reducing the scope of data access. ```rust use std::sync::Arc; use arc_swap::ArcSwap; use arc_swap::cache::{Access, Cache}; struct AppConfig { database_url: String, max_connections: usize, log_level: String, } struct DatabaseConfig { url: String, max_connections: usize, } let config = ArcSwap::from_pointee(AppConfig { database_url: "postgres://localhost/db".to_string(), max_connections: 10, log_level: "info".to_string(), }); let cache = Cache::new(&config); // Create a projected view for just database settings let mut db_cache = cache.map(|cfg| &cfg.database_url); // Component only sees what it needs fn init_database>(config: &mut A) { let url = config.load(); println!("Connecting to: {}", url); } init_database(&mut db_cache); ``` -------------------------------- ### ArcSwapOption - Atomic Optional Value Storage Source: https://context7.com/vorner/arc-swap/llms.txt ArcSwapOption extends ArcSwap to store an Option>, enabling atomic management of values that may or may not be present. It supports initialization with None, storing Some values, and resetting to None. It also provides const initialization for static variables. ```rust use std::sync::Arc; use arc_swap::ArcSwapOption; // Start with None let optional: ArcSwapOption = ArcSwapOption::empty(); assert!(optional.load().is_none()); // Store Some value optional.store(Some(Arc::new("hello".to_string()))); assert_eq!("hello", &***optional.load().as_ref().unwrap()); // Create from value directly let optional = ArcSwapOption::from_pointee(42); assert_eq!(42, **optional.load().as_ref().unwrap()); // Reset to None optional.store(None); assert!(optional.load().is_none()); // Const initialization for statics static GLOBAL: ArcSwapOption = ArcSwapOption::const_empty(); fn init_global() { GLOBAL.store(Some(Arc::new("initialized".to_string()))); } ``` -------------------------------- ### ArcSwap::compare_and_swap - Conditional Atomic Update Source: https://context7.com/vorner/arc-swap/llms.txt The compare_and_swap method provides a way to atomically update a value only if it matches an expected current value. It returns the previous value, indicating whether the swap was successful. This is crucial for implementing lock-free algorithms where updates depend on the state not changing unexpectedly. ```rust use std::sync::Arc; use arc_swap::ArcSwap; use std::ptr; let shared = ArcSwap::from_pointee(42); // Load current value let current = shared.load(); // Try to swap - only succeeds if value hasn't changed let new_value = Arc::new(100); let result = shared.compare_and_swap(&*current, new_value); // Check if swap succeeded by comparing pointers if ptr::eq(&**result, &**current) { println!("Swap succeeded!"); } else { println!("Swap failed - value was changed by another thread"); } // Can also compare against raw pointers let shared = ArcSwap::from_pointee(0); let guard = shared.load(); let old_ptr = Arc::as_ptr(&*guard); shared.compare_and_swap(old_ptr, Arc::new(1)); ``` -------------------------------- ### Replace Stored Value with ArcSwap::store - Rust Source: https://context7.com/vorner/arc-swap/llms.txt Illustrates the `store` method for atomically replacing the currently stored value with a new one. The old value is automatically deallocated when no longer referenced. ```rust use std::sync::Arc; use arc_swap::ArcSwap; let config = ArcSwap::from_pointee("initial"); // Store a new value config.store(Arc::new("updated")); assert_eq!("updated", **config.load()); // Old value is automatically cleaned up let shared = ArcSwap::from_pointee(vec![1, 2, 3]); shared.store(Arc::new(vec![4, 5, 6])); // The old vec![1,2,3] is dropped when no longer referenced ``` -------------------------------- ### Guard for Temporary Value Access in ArcSwap (Rust) Source: https://context7.com/vorner/arc-swap/llms.txt Explains the `Guard` type, which is returned by the `load()` method of `ArcSwap`. The `Guard` provides temporary, dereferenceable access to the stored value and acts as a handle. When all `Guard` instances referencing an old value are dropped, the associated data is deallocated. It can also be converted into an owned `Arc` or created from an existing `Arc`. ```rust use std::sync::Arc; use arc_swap::{ArcSwap, Guard, DefaultStrategy}; let shared = ArcSwap::from_pointee(42); // Guard dereferences to the Arc let guard = shared.load(); let arc: &Arc = &*guard; let value: &i32 = &**guard; assert_eq!(42, *value); // Convert Guard to owned Arc when needed let owned_arc: Arc = Guard::into_inner(shared.load()); assert_eq!(42, *owned_arc); // Create Guard from an Arc (useful for APIs expecting Guard) let my_arc = Arc::new(100); let guard: Guard, DefaultStrategy> = Guard::from_inner(my_arc); assert_eq!(100, **guard); ``` -------------------------------- ### Cache - Optimized Read Access to Shared Data Source: https://context7.com/vorner/arc-swap/llms.txt The Cache struct optimizes read access to data managed by ArcSwap by maintaining a local copy. It performs cheap revalidations on each load and only fetches updated data from the shared storage when necessary, offering significant performance gains for frequent reads. ```rust use std::sync::Arc; use arc_swap::{ArcSwap, Cache}; let shared = Arc::new(ArcSwap::from_pointee(42)); // Create a cache for faster repeated access let mut cache = Cache::new(Arc::clone(&shared)); // Loads are very fast when value hasn't changed (~10-25x faster) for _ in 0..1000 { let value = cache.load(); println!("{}", **value); } // Cache automatically updates when shared value changes shared.store(Arc::new(100)); let value = cache.load(); // Detects change, fetches new value assert_eq!(100, **value); // Works great in thread-local storage use std::cell::RefCell; thread_local! { static CONFIG_CACHE: RefCell>, Arc>> = RefCell::new(Cache::new(Arc::new(ArcSwap::from_pointee("default".to_string())))); } ``` -------------------------------- ### ArcSwap::rcu - Atomic Updates with Retry Source: https://context7.com/vorner/arc-swap/llms.txt The rcu method allows for atomic updates to a value within an ArcSwap. It takes a closure that receives the current value and returns the new value. If a concurrent update occurs, the operation automatically retries until it succeeds. This is useful for complex updates on shared data structures like HashMaps. ```rust use std::sync::Arc; use arc_swap::ArcSwap; use std::collections::HashMap; let counter = ArcSwap::from_pointee(0); // Atomically increment - retries if concurrent modification detected counter.rcu(|current| **current + 1); assert_eq!(1, **counter.load()); // Complex updates on collections let cache: ArcSwap> = ArcSwap::default(); // Add entry atomically cache.rcu(|current| { let mut new_cache = HashMap::clone(current); new_cache.insert("key".to_string(), 42); new_cache }); assert_eq!(Some(&42), cache.load().get("key")); // Multiple concurrent updates work correctly use std::thread; let shared = Arc::new(ArcSwap::from_pointee(0)); let threads: Vec<_> = (0..10).map(|_| { let shared = Arc::clone(&shared); thread::spawn(move || { for _ in 0..100 { shared.rcu(|val| **val + 1); } }) }).collect(); for t in threads { t.join().unwrap(); } assert_eq!(1000, **shared.load()); ```