AppState

Struct AppState 

Source
pub struct AppState { /* private fields */ }
Expand description

A type-safe container for shared application state.

AppState allows you to store multiple different types of state in a single container. Each type is identified by its TypeId, ensuring type safety when retrieving state.

§Thread Safety

AppState is fully thread-safe and can be cloned cheaply (uses Arc internally). Multiple handlers can access the same state concurrently without additional synchronization.

§Memory Management

State is stored using Arc, so cloning AppState or extracting state with the State extractor only increments a reference count. The actual state data is shared across all references.

§Type Requirements

Types stored in AppState must be:

  • Send: Can be sent between threads
  • Sync: Can be referenced from multiple threads
  • 'static: Has a static lifetime

§Examples

§Creating and Using State

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

// Create empty state
let state = AppState::new();

// Add some data
state.insert(Arc::new("Hello".to_string()));
state.insert(Arc::new(42_u32));

// Retrieve data
let text: Option<Arc<String>> = state.get();
assert_eq!(*text.unwrap(), "Hello");

let number: Option<Arc<u32>> = state.get();
assert_eq!(*number.unwrap(), 42);

§With Router

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

struct AppConfig {
    name: String,
    version: String,
}

async fn info_handler(State(config): State<Arc<AppConfig>>) -> Result<String> {
    Ok(format!("{} v{}", config.name, config.version))
}

let config = Arc::new(AppConfig {
    name: "MyApp".to_string(),
    version: "1.0.0".to_string(),
});

let router = Router::new()
    .with_state(config)
    .default_handler(handler(info_handler));

§Complex State Management

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

struct UserStore {
    users: tokio::sync::RwLock<HashMap<u64, String>>,
}

impl UserStore {
    fn new() -> Self {
        Self {
            users: tokio::sync::RwLock::new(HashMap::new()),
        }
    }

    async fn add_user(&self, id: u64, name: String) {
        self.users.write().await.insert(id, name);
    }

    async fn get_user(&self, id: u64) -> Option<String> {
        self.users.read().await.get(&id).cloned()
    }
}

async fn user_handler(
    State(store): State<Arc<UserStore>>,
) -> Result<String> {
    store.add_user(1, "Alice".to_string()).await;
    let user = store.get_user(1).await;
    Ok(format!("User: {:?}", user))
}

Implementations§

Source§

impl AppState

Source

pub fn new() -> AppState

Creates a new empty AppState.

The state starts with no data. Use insert to add state.

§Examples
use wsforge::prelude::*;

let state = AppState::new();
Source

pub fn insert<T>(&self, value: Arc<T>)
where T: Send + Sync + 'static,

Inserts a value into the state.

If a value of the same type already exists, it will be replaced. The value is automatically wrapped in an Arc.

§Type Requirements

The type T must implement:

  • Send: Can be transferred across thread boundaries
  • Sync: Can be safely shared between threads
  • 'static: Has a static lifetime (no borrowed data)
§Arguments
  • value - The value to store in state
§Examples
§Basic Usage
use wsforge::prelude::*;
use std::sync::Arc;

let state = AppState::new();

// Insert different types
state.insert(Arc::new(String::from("Hello")));
state.insert(Arc::new(42_u32));
state.insert(Arc::new(true));
§Replacing Values
use wsforge::prelude::*;
use std::sync::Arc;

let state = AppState::new();

state.insert(Arc::new(10_u32));
assert_eq!(*state.get::<u32>().unwrap(), 10);

// Replace with new value
state.insert(Arc::new(20_u32));
assert_eq!(*state.get::<u32>().unwrap(), 20);
§Custom Types
use wsforge::prelude::*;
use std::sync::Arc;

struct Database {
    url: String,
}

let state = AppState::new();

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

state.insert(db);
Source

pub fn get<T>(&self) -> Option<Arc<T>>
where T: Send + Sync + 'static,

Retrieves a value from the state by its type.

Returns None if no value of type T has been stored. Returns Some(Arc<T>) if a value exists.

§Type Safety

The returned value is guaranteed to be of type T because values are stored and retrieved using TypeId.

§Performance

This operation is O(1) and lock-free, making it very efficient even with concurrent access from multiple threads.

§Examples
§Basic Retrieval
use wsforge::prelude::*;
use std::sync::Arc;

let state = AppState::new();
state.insert(Arc::new(String::from("Hello")));

let text: Option<Arc<String>> = state.get();
assert_eq!(*text.unwrap(), "Hello");

// Trying to get a type that doesn't exist
let number: Option<Arc<u32>> = state.get();
assert!(number.is_none());
§Pattern Matching
use wsforge::prelude::*;
use std::sync::Arc;

let state = AppState::new();
state.insert(Arc::new(42_u32));

match state.get::<u32>() {
    Some(value) => println!("Found: {}", value),
    None => println!("Not found"),
}
§Multiple Types
use wsforge::prelude::*;
use std::sync::Arc;

struct Config { port: u16 }
struct Database { url: String }

let state = AppState::new();
state.insert(Arc::new(Config { port: 8080 }));
state.insert(Arc::new(Database { url: "...".to_string() }));

// Each type is stored separately
let config: Arc<Config> = state.get().unwrap();
let db: Arc<Database> = state.get().unwrap();

println!("Port: {}, DB: {}", config.port, db.url);
§With Error Handling
use wsforge::prelude::*;
use std::sync::Arc;

struct Database;

let state = AppState::new();

let db = state
    .get::<Database>()
    .ok_or_else(|| Error::custom("Database not configured"))?;

// Use db...
Source

pub fn contains<T>(&self) -> bool
where T: Send + Sync + 'static,

Checks if a value of type T exists in the state.

This is equivalent to state.get::<T>().is_some() but more explicit.

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

let state = AppState::new();
state.insert(Arc::new(42_u32));

assert!(state.contains::<u32>());
assert!(!state.contains::<String>());
Source

pub fn remove<T>(&self) -> Option<Arc<T>>
where T: Send + Sync + 'static,

Removes a value of type T from the state.

Returns the removed value if it existed, or None otherwise.

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

let state = AppState::new();
state.insert(Arc::new(42_u32));

assert!(state.contains::<u32>());

let value = state.remove::<u32>();
assert_eq!(*value.unwrap(), 42);

assert!(!state.contains::<u32>());
Source

pub fn len(&self) -> usize

Returns the number of different types stored in the state.

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

let state = AppState::new();
assert_eq!(state.len(), 0);

state.insert(Arc::new(String::from("Hello")));
assert_eq!(state.len(), 1);

state.insert(Arc::new(42_u32));
assert_eq!(state.len(), 2);

// Replacing same type doesn't increase count
state.insert(Arc::new(100_u32));
assert_eq!(state.len(), 2);
Source

pub fn is_empty(&self) -> bool

Checks if the state is empty (contains no data).

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

let state = AppState::new();
assert!(state.is_empty());

state.insert(Arc::new(42_u32));
assert!(!state.is_empty());
Source

pub fn clear(&self)

Clears all state data.

Removes all stored values, leaving the state empty.

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

let state = AppState::new();
state.insert(Arc::new(String::from("Hello")));
state.insert(Arc::new(42_u32));

assert_eq!(state.len(), 2);

state.clear();

assert_eq!(state.len(), 0);
assert!(state.is_empty());

Trait Implementations§

Source§

impl Clone for AppState

Source§

fn clone(&self) -> AppState

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Default for AppState

Source§

fn default() -> AppState

Returns the “default value” for a type. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more