topo 0.9.1

Reified activation records and scoped thread-locals for UI runtimes.

topo creates a hierarchy of scoped, nested [environments][topo::Env] whose shape matches the function callgraph. These environments store singletons indexed by their type, and references to environmental values are available only to an enclosed call scope. When a #![topo::nested] function is called, its parent environment is cheaply propagated along with any additional values added at appropriate callsites.

Each environment in this hierarchy has a unique and deterministic [topo::Id] describing that environment and the path taken to arrive at its stack frame. These identifiers are derived from the path taken through the callgraph to the current location, and are stable across repeated invocations of the same execution paths.

By running the same topologically-nested functions in a loop, we can observe changes to the structure over time. The moxie crate uses these identifiers and environments to create persistent trees for rendering human interfaces.

Making functions nested within the call topology

Defining a topological function results in a macro definition for binding the function to each callsite where it is invoked. Define a topologically-nested function with the topo::nested attribute:

#[topo::nested]
fn basic_topo() -> topo::Id { topo::Id::current() }

#[topo::nested]
fn tier_two() -> topo::Id { basic_topo!() }

// each of these functions will be run in separately identified
// contexts as the source locations for their calls are different
let first = basic_topo!();
let second = basic_topo!();
assert_ne!(first, second);

let third = tier_two!();
let fourth = tier_two!();
assert_ne!(third, fourth);
assert_ne!(first, third);
assert_ne!(first, fourth);
assert_ne!(second, fourth);

Because topological functions must be sensitive to the location at which they're invoked and within their immediate parent, we transform the function definition into a macro to track the source location at which it is called. Future language features may make it possible to call topo-nested functions without any special syntax.