topcoat 0.11.0

A modular, batteries-included Rust web framework for server-rendered apps.
Documentation
# App context

App context shares values across requests. Register a value on the router, then borrow it with `app_context(cx)` wherever you have a request context. A database pool is a typical app context value.

Values are identified by their Rust type. The router accepts one value of each type.

## Registering values

Build the router and chain `.app_context(value)` for every value you want to share:

```rust,standalone_crate
use topcoat::router::{Router, RouterBuilderDiscoverExt, module_router};

pub fn router() -> Router {
    module_router!()
        .discover()
        .app_context(Database::connect())
        .app_context(HttpClient::new())
        .build()
}
```

Registering two values of the same type panics. Wrap them in distinct types when you need to share both:

```rust,standalone_crate
use topcoat::router::module_router;
struct PrimaryDb(Database);
struct ReplicaDb(Database);

module_router!()
    .app_context(PrimaryDb(Database::connect_primary()))
    .app_context(ReplicaDb(Database::connect_replica()))
    .build();
```

## Reading values

Inside any handler that has access to a `Cx`, call `app_context::<T>(cx)` to borrow the registered value:

```rust
use topcoat::{
    context::{Cx, app_context},
    Result,
    router::page,
    view::{View, view},
};

#[page]
async fn user_profile(cx: &Cx) -> Result<impl View> {
    let db: &Database = app_context(cx);
    let user = db.fetch_user(42).await;
    Ok(view! { <h1>"Hello, " (user.name) </h1> })
}
```

The requested type must exactly match the registered type. `app_context` panics if that type was not registered.

When an app context value is intentionally optional, use `try_app_context::<T>(cx)` instead. It returns `None` when the type was not registered:

```rust
use topcoat::context::{Cx, try_app_context};
#
# struct FeatureConfig;

fn feature_config(cx: &Cx) -> Option<&FeatureConfig> {
    try_app_context(cx)
}
```

## Requirements

The value must implement `Any + Send + Sync`. The `Any` bound requires it to be `'static`, so it cannot borrow temporary data.

Requests borrow the registered value. The value does not need to implement `Clone`.