Module state

Module state 

Source
Expand description

Shared application state management.

This module provides a type-safe, thread-safe container for storing and retrieving application state that needs to be shared across all WebSocket connections. State is commonly used for database connections, configuration, caches, and other shared resources.

§Overview

The AppState type uses a type-map pattern, allowing you to store multiple different types of state in a single container. Each type is stored separately and can be retrieved by its type, ensuring type safety at compile time.

§Design

  • Type-safe: Each state type is stored and retrieved by its exact type
  • Thread-safe: Uses Arc and DashMap for lock-free concurrent access
  • Zero-cost abstraction: No runtime overhead when state is not used
  • Flexible: Any type that is Send + Sync + 'static can be stored

§Common Use Cases

Use CaseExample TypeDescription
DatabaseArc<DatabasePool>Shared database connection pool
ConfigurationArc<Config>Application settings and configuration
CacheArc<Cache>In-memory cache for frequently accessed data
MetricsArc<Metrics>Performance metrics and monitoring
Connection ManagerArc<ConnectionManager>Manage all active WebSocket connections

§Examples

§Single State Type

use wsforge::prelude::*;
use std::sync::Arc;

struct Database {
    connection_string: String,
}

async fn query_handler(State(db): State<Arc<Database>>) -> Result<String> {
    Ok(format!("Connected to: {}", db.connection_string))
}

let db = Arc::new(Database {
    connection_string: "postgres://localhost/mydb".to_string(),
});

let router = Router::new()
    .with_state(db)
    .default_handler(handler(query_handler));

§Multiple State Types

use wsforge::prelude::*;
use std::sync::Arc;

struct Database {
    url: String,
}

struct Config {
    max_connections: usize,
    timeout_seconds: u64,
}

struct Cache {
    data: std::collections::HashMap<String, String>,
}

async fn handler(
    State(db): State<Arc<Database>>,
    State(config): State<Arc<Config>>,
    State(cache): State<Arc<Cache>>,
) -> Result<String> {
    Ok(format!(
        "DB: {}, Max: {}, Cache size: {}",
        db.url,
        config.max_connections,
        cache.data.len()
    ))
}

let router = Router::new()
    .with_state(Arc::new(Database { url: "...".to_string() }))
    .with_state(Arc::new(Config { max_connections: 100, timeout_seconds: 30 }))
    .with_state(Arc::new(Cache { data: Default::default() }))
    .default_handler(handler(handler));

§Mutable State with RwLock

use wsforge::prelude::*;
use std::sync::{Arc, RwLock};

struct Counter {
    value: RwLock<u64>,
}

impl Counter {
    fn increment(&self) {
        let mut value = self.value.write().unwrap();
        *value += 1;
    }

    fn get(&self) -> u64 {
        *self.value.read().unwrap()
    }
}

async fn count_handler(State(counter): State<Arc<Counter>>) -> Result<String> {
    counter.increment();
    Ok(format!("Count: {}", counter.get()))
}

let counter = Arc::new(Counter {
    value: RwLock::new(0),
});

let router = Router::new()
    .with_state(counter)
    .default_handler(handler(count_handler));

Structs§

AppState
A type-safe container for shared application state.