#compose #struct #derive #proc-macro #structify

macro structify-derive

A procedural macro to transform functions into structs with state and execution dependencies

1 unstable release

0.1.0 Oct 11, 2024

#44 in #compose

Download history 101/week @ 2024-10-05 60/week @ 2024-10-12 2/week @ 2024-10-19

163 downloads per month
Used in structify

MIT license

10KB
95 lines

structify

structify is a Rust crate that provides a procedural macro to transform functions into structs with state and execution dependencies.

Features

  • Struct Generation: Automatically generate structs from functions using the #[structify] attribute.
  • Dependency Injection: Manage execution dependencies seamlessly with the Dep<T> type.
  • Async Support: Compatible with both synchronous and asynchronous functions.
  • Custom Struct Names: Optionally specify custom names for generated structs.
  • State Management: Handle state within structs to maintain clean and modular code.

Installation

Add structify to your Cargo.toml dependencies:

[dependencies]
structify = "0.1.0"  # Replace with the actual version

Import the macro in your crate:

use structify::structify;

Usage

Basic Function Transformation

Annotate a function with #[structify] to generate a struct with new() and execute() methods:

#[structify]
fn greet() {
    println!("Hello, World!");
}

fn main() {
    Greet::new().execute();
}

Functions with Arguments and Return Values

Functions with parameters will have those parameters as fields in the generated struct:

#[structify]
fn add(a: i32, b: i32) -> i32 {
    a + b
}

fn main() {
    let result = Add::new(2, 3).execute();
    assert_eq!(result, 5);
}

Using Dependencies with Dep<T>

Use Dep<T> to inject dependencies or state into your functions:

use structify::Dep;

#[structify]
fn increment(value: i32, state: Dep<i32>) -> i32 {
    value + *state.inner()
}

fn main() {
    let state = Dep::new(10);
    let result = Increment::new(5).execute(state);
    assert_eq!(result, 15);
}

Mixing Arguments and Dependencies

You can mix regular arguments and dependencies:

#[structify]
fn compute(a: i32, state: Dep<i32>, b: i32) -> i32 {
    a + *state.inner() + b
}

fn main() {
    let state = Dep::new(20);
    let result = Compute::new(5, 10).execute(state);
    assert_eq!(result, 35);
}

Custom Struct Names

Specify a custom name for the generated struct using attributes:

#[structify(CustomName)]
fn my_function() {
    // Function body
}

fn main() {
    CustomName::new().execute();
}

Asynchronous Functions

Annotate async functions to generate structs that support asynchronous execution:

#[structify]
async fn fetch_data() -> String {
    // Simulate fetching data asynchronously
    "Data fetched".to_string()
}

#[tokio::main]
async fn main() {
    let result = FetchData::new().execute().await;
    println!("{}", result);
}

How It Works

The #[structify] macro transforms the annotated function into a struct:

  • Struct Fields: Parameters of the function become fields of the struct.
  • Constructor (new()): Initializes the struct with provided arguments.
  • Execution Method (execute()): Executes the original function, injecting any dependencies.

Dependencies are handled via the Dep<T> type, which uses Arc<T> for shared ownership and thread safety.

Examples

Stateful Computation with Dependencies

use structify::{structify, Dep};

#[structify]
fn multiply_and_add(x: i32, multiplier: Dep<i32>, adder: i32) -> i32 {
    x * *multiplier.inner() + adder
}

fn main() {
    let multiplier = Dep::new(3);
    let result = MultiplyAndAdd::new(5, 2).execute(multiplier);
    assert_eq!(result, 17); // (5 * 3) + 2
}

Asynchronous Processing

use structify::structify;

#[structify]
async fn async_compute(a: i32, b: i32) -> i32 {
    a + b
}

#[tokio::main]
async fn main() {
    let result = AsyncCompute::new(10, 20).execute().await;
    assert_eq!(result, 30);
}

Limitations

  • Lifetime Support: Currently, the macro does not support functions with lifetime parameters or references.

Contributing

Contributions are welcome! Feel free to open issues or submit pull requests on GitHub.

License

This project is licensed under the MIT License.

Dependencies

~0.6–1.1MB
~21K SLoC