Crete
Crete is a procedural macro that simplifies state management in Rust, in a flexible way.
It generates code for atomic access to a struct's fields using an RwLock and a static store, making it easier to work
with shared state in both synchronous and asynchronous contexts.
Because users can implement practically anything on the struct, Crete allows for a flexible store that can be tailored to a variety of needs. Perhaps you'd like to use to build a Redux-style store. Perhaps you enjoy having a billion custom setters. Perhaps you just enjoy mutating everything directly. Or maybe you even have your own homemade style of setters and getters that you love best?
No restrictions.
Features
-
Ergonomic, intuitive Design
Reduces boilerplate with a straightforward interface for managing state. -
Synchronous and Asynchronous Support
Works seamlessly in both synchronous and asynchronous environments. -
Versatile Clone Support
Adapts to your needs by supporting both cloneable and non-cloneable types. -
No shoehorning
Build the State management style you enjoy best on top... or not.
Details
-
Generates code for atomic, thread-safe access to a struct by defining a static store typically within a module that holds and manages the shared state.
-
Generates unit structs (e.g.
FooField,BarField) and implements aFieldtrait for each, enabling type-safe access and update of individual fields.
This macro produces:
-
A static store (a
LazyLockholding anRwLockprotecting anArcof the struct) whose identifier is based on the struct name (e.g.CRETE_FOOfor a struct namedFoo). -
An implementation of several associated methods on the struct:
new(): constructs a new instance using the struct'sDefaultimplementation. Called byLazyLock.read(): returns anArc-wrapped shared reference to the current state.clone(): (if the struct implementsClone) returns a cloned instance of the stored value. Available only forTthat derivesClone.write(self): atomically replaces the current stored value with the provided one.select_ref<F: Field>(&self, field: F) -> &F::FieldType: returns a reference to the selected field.get<F, R>(field: F, f: impl FnOnce(&F::FieldType) -> R) -> R: applies a closure to a shared reference of the selected field.select<F: Field>(field: F) -> F::FieldType: returns a cloned value of the selected field. Available only forTthat derivesClone.set<F>(field: F, value: F::FieldType): updates a specific field and writes the new state to the store.update(f: impl FnOnce(&mut Self)): applies a mutation closure to the current state and updates the store.update_async(f: impl AsyncFnOnce(&mut Self)): an asynchronous version ofupdatefor non-blocking mutations.
The generated code leverages std::sync::LazyLock, RwLock, and Arc to ensure that all operations
are safe to use concurrently from multiple threads.
How it works
Static Store
A static store is created for the user's struct, allowing atomic access to its state:
When T is Clone:
Otherwise:
With a struct like this:
use crete;
You can now do this:
Async closure support
async
No Clone, No Problem
It works the same way, except:
select()does not exist for fields that are not clone-able.clone()does not exist for the static Struct.
Clone inference
The proc macro tries to infer if the struct derives Clone. This works if you place it before the derive macro.
// Works
You can also be explicit about it (also useful if you impl Clone instead of deriving it):
// Works
This won't work:
// Fails
But this will work:
// Works
Considerations
Under the hood
There is a different implementation depending on your struct.
Clone store
In this case, we use RwLock<Arc<T>>. This means readers are not blocked by writers.
Non-clone store
In this case, we use Arc<RwLock<T>. This means both readers and writers block.
RwLock
You are using RwLock behind the scenes. The usual considerations for locking in multithreaded code apply.
In essence:
- Don't let your thread panic while it holds a write lock.
- If the thread already has acquired a lock, don't try to get it again before it drops.
FAQ
What's with the name?
- It's interestingly confusing with
crate. - It's the name of the island the crate author spends lots of his time at.
License
This project is licensed under the MIT License._