# Scopes and lifetimes

> Where a screen's state lives, how long it lives, and why nothing can keep it alive past its screen.

The store holds the facts your screens present. It is divided into scopes. Each scope is one Rust struct, provided by one type, keyed by who owns it. How long a scope lives is decided by one rule: **a scope lives exactly as long as its node is on the path.**

## The three lifetimes

A scope's key is a `Scope`:

```rust
pub enum Scope {
    Process,
    Node(RouteId),
}
```

That gives three lifetimes:

| Key | Lives |
| --- | --- |
| `Scope::Process` | From the moment it is provided until the store is dropped |
| `Scope::Node(id)`, `id` structural | While `id` is on the path, which spans all its children |
| `Scope::Node(id)`, `id` a view or instance root | While that screen is on the path |

Use `Process` for facts the whole app shows, such as a theme setting or the list of documents. Use a node scope for state that belongs to one screen, such as an editor's word count. Declare a [structural node](/docs/routing/tables#tiers) when some state must outlive several sibling screens, such as a signed-in session that spans a lobby and a game.

## Providing a scope

```rust
const EDITOR: Scope = Scope::Node("note");

let mut store = Store::over(&table());
store.provides::<Editor>(EDITOR)?;
```

`Store::over` builds a store that knows the table's ids, so a scope keyed on a misspelled id fails here with `StoreError::UnknownNode`, instead of never mounting. `Store::new()` builds one without that check.

`provides` takes a type and **no value**. A scope's first value comes from its schema's declared starting values. See [Schemas](/docs/state/schemas). The type must implement `Schema` and `Clone` and be `'static`. The `ScopeSchema` trait names those bounds and is implemented for you. Each field you set must also implement `PartialEq`, because every set is compared with the value already there.

A process scope mounts as soon as it is provided. A node scope waits for its node to join the path.

One scope has one provider. Providing a second time is `StoreError::AlreadyProvided`. A scope's schema must be a record of named fields, or `provides` returns `StoreError::NotARecord`.

## Mounting is the walk's job

When `router.resolve` moves the path, it drops the scopes of nodes that left and mounts the scopes of nodes that joined, at their declared starting values. `leave` runs before the drop, so a departing node can still read its scope. `enter` runs after the mount, so an arriving node finds its scope in place.

There is no public way to mount or unmount a scope. That is deliberate. If you could mount one by hand, you could keep one alive past its screen, and stale state that outlived its screen would be back. Instead, state from one editing session simply cannot leak into the next. The notes example tests this: reopen a note and its editor starts from the saved text, not the abandoned draft.

## Reading

```rust
if let Some(e) = store.read::<Editor>(EDITOR) {
    println!("{} ({} words)", e.title, e.words);
}
```

`read` returns `&T` of the last committed value, or `None` while the scope is not mounted. There is no map or lookup on the read path. You downcast once and read fields directly.

Other read-side questions:

| Method | Answers |
| --- | --- |
| `is_mounted(scope)` | Whether the scope exists right now |
| `version(scope)` | A stamp that changes on every commit that changed it, and on mount and unmount. `0` when not mounted |
| `reflection(scope)` | The schema's `Kind`, for validation and diagnostics |
| `provided_as::<T>(scope)` | Whether the scope is provided as `T` |

Version stamps come from one counter for the whole store, so a scope that leaves and comes back never reuses a stamp. A renderer can hold the last stamp it drew and compare one integer.

`read` with the wrong type returns `None` and fails a debug assertion. If your code reads a scope that something else provides, call `provided_as` once at startup, which returns `StoreError::WrongType` naming both types, instead of finding out on the first frame the screen opens.

## Subscribing

Reading is pull: you read what you need each frame. Subscribing is push: you are told when a field you care about changed.

```rust
let watcher = store.subscriber();
store.subscribe(watcher, EDITOR, "dirty")?;
```

A `SubscriberId` is an opaque id, not a callback. After each tick, the `Notice` says who is owed a re-render. See [Producers and the tick](/docs/state/producers). You can subscribe to a node scope that is not mounted yet. A scope mounting or unmounting wakes its subscribers too, on the next tick. `unsubscribe_all(who)` drops every subscription a subscriber holds.

## Fields are top level

A scope's fields are the record's top-level fields. A nested struct is one field and changes as a whole. A `Vec` is one field, so changing one row wakes everyone watching the list. Keyed collections are not built yet. If you need finer updates, flatten.

## What belongs in a scope

The store carries facts about what should be presented, not the presentation's bulk data. A selected id, a title, a count, a flag: yes. A vertex buffer, an image, ten thousand rows: no. A scope is cloned on every commit that touched it, so bulk data costs you every frame. Keep large data in your model and put the facts about it in the store.

## Next

[Schemas](/docs/state/schemas): describing a scope's struct so the store can mount it.
