#proc-macro #compile-time #state #global #key-value #storing #run-time

macro_state

A set of macros allowing storing and loading global state at compile-time within proc macros

12 releases

0.2.1 Oct 3, 2024
0.2.0 Oct 18, 2022
0.1.9 Oct 13, 2022
0.1.5 Jun 4, 2022
0.1.2 May 30, 2022

#2234 in Procedural macros

Download history 307/week @ 2024-07-20 274/week @ 2024-07-27 176/week @ 2024-08-03 416/week @ 2024-08-10 327/week @ 2024-08-17 252/week @ 2024-08-24 235/week @ 2024-08-31 238/week @ 2024-09-07 228/week @ 2024-09-14 331/week @ 2024-09-21 387/week @ 2024-09-28 228/week @ 2024-10-05 270/week @ 2024-10-12 244/week @ 2024-10-19 286/week @ 2024-10-26 123/week @ 2024-11-02

947 downloads per month
Used in 2 crates

MIT license

23KB
253 lines

macro_state

DEPRECATED

This crate is built upon some underlying UB (undefined behavior) in the rust compiler and is very likely to break in random circumstances outside of your control. For a safer option that allows for similar behavior, please consider using the outer macro pattern combined with my macro_magic crate.

macro_state is now in archive mode and will no longer be actively updated.

crates.io GitHub Workflow Status (branch) docs.rs

Currently, Rust does not provide the ability to keep track of any sort of global state between macro calls out of the box.

This crate contains a series of macros that make it trivial to save and load global state (in the form of string keys and values) at compile time and from within proc macros. State that was set at compile-time can also be read directly by runtime code, if needed.

Functionality

The write_state! and append_state! macros store state in flat files that live in the target build directory for the current project. This ensures that when you do things like run cargo clean or change your code, the current state values are automatically reset as well. In other words, this crate automatically tracks with the build artifacts of whatever is using it.

After compilation, whatever values were present at compile-time are baked into the resulting binary.

Macros

Currently, we offer the following macros:

  • write_state!("key","value") writes "value" as the value for the key "key"
  • read_state!("key") returns the value for the key "key", issuing a compiler error if it can't be found
  • init_state!("key","value") if the key "key" has a value, returns it, otherwise sets it to "value" and also returns it. This can be used to quickly initialize a key value pair that may have existing data
  • has_state!("key") returns a boolean indicating whether a value has been stored for the key "key"
  • clear_state!("key") clears any existing state value for key "key", if it exists
  • append_state!("key","value") appends "value" to the value list for the specified key. Used in conjunction with read_state_vec! to add to and manage lists within state files.
  • read_state_vec!("key") reads the state file for key "key" as a Vec<String>. Used in conjunction with append_state! to manage manage lists within state files.

Within Proc Macros

Non-macro analogues for all of the macros listed above can be found here. These analogues all begin with proc_, such as proc_read_state, and should only be used within proc macros.

Using these functions anywhere but within a proc macro will result in broken/undefined behavior.

Installation

First add macro_state as a dependency in your Cargo.toml file:

[dependencies]
macro_state = "0.1.9"

Next set up your imports:

extern crate macro_state;
use macro_state::*;

Usage

Now you can call write_state! and read_state! anywhere in your crate, including inside of proc macros!

write_state!("top of module", "value 1");

#[test]
fn test_write_state() {
    write_state!("top of method", "value 2");
    assert_eq!(read_state!("top of module"), "value 1");
    assert_eq!(read_state!("top of method"), "value 2");
}

After writing a call to write_state, such as write_state!("my key", "my value");, the state you wrote will now be available at the specified key for use by read_state!("my key"); calls further down in your source code. Note that all of this happens at compile-time, so make sure your source code and macro calls are laid out such that your write_state calls will be compiled before your read_state calls.

Dependencies

~1.5MB
~37K SLoC