Skip to main content

Crate compose_rust_macros

Crate compose_rust_macros 

Source
Expand description

#[composable]: what the Compose compiler plugin does to a function, done from outside the compiler.

The plugin does three things to a @Composable function, and this does the same three to a Rust one:

  1. It gives the call a group, keyed by where the function is declared. A slot table stores what a call site remembered at a position, and the group is what turns a position into an identity: two calls of the same function in one parent are told apart by order, and everything the function remembers belongs to its group alone.

  2. It gives every branch a group of its own: each arm of an if, an else and a match. Without one, the state a branch remembered is handed to whichever call occupies its position after the branch stops being taken. Both values are often the same type, so nothing complains, and the screen silently shows one widget’s state in another.

    Loop bodies get no group, as in Compose. Each pass of a loop calls the same call sites again, and the runtime tells the passes apart by order, which is what a list that only grows and shrinks at the end needs. A list whose items move needs to say which item is which, and that is key(id, || ..): a group per iteration here would sit between the loop and the key and pin every item to its position.

  3. It makes the function skippable and restartable. The parameters are compared with the ones the group was last run with, and when they are all equal and nothing the function read has changed, its body is not run at all. When a state it read changes, the runtime runs this function again on its own, with the parameters it last had, without running whatever called it.

A group closes when a guard bound at the top of its block is dropped, not when a closure wrapping the block returns. A local with a destructor is dropped after the block’s tail expression has been evaluated, so the group closes in the right place on an ordinary exit, and closes anyway on continue, break, return, ? and an unwind. Wrapping the body in a closure would make the first two compile errors and give return a different meaning.

What can be compared and stored is decided from the parameter’s type as written. A parameter whose type borrows (other than &'static), names a generic parameter, or is impl Trait cannot be kept past the call, so a function with one is never skipped and is re-run by its caller rather than on its own. A parameter that can be kept but is not Clone + PartialEq is found out at compile time by method resolution and treated the same way. Nothing here needs the function’s author to say which is which.

Attribute Macros§

composable
Turns a function into a composable.