MoosicBox Async Macros
Procedural macros for async function transformation and yield injection.
Overview
The MoosicBox Async Macros package provides:
- Yield Injection: Automatic yield point insertion for simulation testing
- Async Transformation: Transform async functions for deterministic execution
- Proc Macros:
#[inject_yields]andinject_yields_mod!macros - Feature-Gated: Only active when
simulatorfeature is enabled - AST Manipulation: Sophisticated syntax tree transformation
Features
Yield Injection
- Automatic Yields: Insert yield points after every
.await - Deterministic Testing: Enable predictable async execution in tests
- Simulation Support: Required for simulation-based testing
- Non-Intrusive: No overhead when simulator feature is disabled
Macro Types
#[inject_yields]: Attribute macro for individual functions and impl blocksinject_yields_mod!: Procedural macro for entire modules- Conditional: Only active with
simulatorfeature flag
AST Transformation
- Await Wrapping: Wraps
.awaitexpressions with yield points - Function Support: Handles async functions and methods
- Module Support: Process entire modules recursively
- Impl Block Support: Transform all async methods in impl blocks
Installation
Add this to your Cargo.toml:
[]
= { = "../async/macros" }
# Enable for simulation testing
= {
path = "../async/macros",
= ["simulator"]
}
Usage
Function-Level Macro
use inject_yields;
// Original function
async
// With simulator feature enabled, transforms to:
// async fn my_async_function() {
// let result1 = {
// let __yield_res = some_async_operation().await;
// ::switchy::unsync::task::yield_now().await;
// __yield_res
// };
// let result2 = {
// let __yield_res = another_async_operation().await;
// ::switchy::unsync::task::yield_now().await;
// __yield_res
// };
// result1 + result2
// }
Impl Block Macro
use inject_yields;
Module-Level Macro
use inject_yields_mod;
// Transform entire module
inject_yields_mod!
Feature-Gated Behavior
// Without simulator feature - no transformation
async
// With simulator feature - yield injection enabled
async
Transformation Details
Await Expression Transformation
Before:
let result = async_call.await;
After (with simulator feature):
let result = ;
Supported Constructs
- Async Functions:
async fndeclarations - Async Methods: Methods in impl blocks
- Nested Modules: Recursive module processing
- Complex Expressions: Handles complex await expressions
Unsupported/Unchanged
- Sync Functions: Non-async functions remain unchanged
- Await in Macros: Await expressions inside macro calls
- Non-Simulator: No transformation without simulator feature
Use Cases
Simulation Testing
Library Development
// Library functions that need deterministic testing
pub async
Feature Flags
simulator: Enable yield injection transformation
Dependencies
- Proc Macro: Procedural macro framework
- Syn: Rust syntax parsing and AST manipulation
- Quote: Code generation utilities
Integration
This package is designed for:
- Testing: Deterministic async testing with simulation
- Development: Consistent async behavior during development
- Library Development: Libraries that need predictable async execution
- Debugging: Easier debugging of async code with controlled execution
Performance
- Zero Cost: No runtime overhead when simulator feature is disabled
- Compile Time: Transformation happens at compile time
- Minimal Impact: Only affects functions with the attribute
- Conditional: Completely conditional based on feature flags