| Crates.io | state-macro |
| lib.rs | state-macro |
| version | 0.1.1 |
| created_at | 2025-04-17 08:17:48.210544+00 |
| updated_at | 2025-05-27 12:17:35.497497+00 |
| description | Syntax sugar for stateful functions |
| homepage | |
| repository | https://github.com/statusfailed/state-macro |
| max_upload_size | |
| id | 1637367 |
| size | 44,039 |
A rust macro for decluttering mutable state computations. Suppose you want to write this:
// some type like this
type State<S> = Rc<RefCell<S>>
fn dense(state: State<S>, x: Var) -> Var {
// this expression is messy!
let x = mat_mul(state, param(state), x) + param(state);
let y = param(state);
This library lets you instead write
#[stateful(State<S>)]
fn dense(x: Var) -> (Var, Var) {
let x = ::mat_mul(::param(), x) + ::param();
let y = ::param();
(x, y)
}
The idea is to make functions stateful by abusing Rust's syntax for the root namespace.
This means you cannot directly refer to the root namespace inside a #stateful annotated function.
You can use the with_state! macro to work around this problem if necessary.
Writing ::f is analogous to !f with
Haskell's Monadic Bang
notation.
#[stateful(T)] transforms the function by:
with_state!.So the example above becomes:
fn dense(state: State<S>, x: Var) -> (Var, Var) {
with_state! { state;
let x = ::mat_mul(::param(), x) + ::param();
let y = ::param();
(x, y)
}
}
Of course, you can also write stateful computations inline using the
with_state! macro directly, which works by:
; tokenNOTE: the contents of with_state! after the first ; can be arbitrary lines
of rust code; essentially the 'innards' of a block.
But when inlining the macro, these will not be wrapped in a block.
So the code above inlines as follows:
fn dense(state: State<S>, x: Var) -> (Var, Var) {
// hijack :: prefix to mean "inject a state param".
let x = mat_mul(state, param(state), x) + param(state);
let y = param(state);
(x, y)
}