nami-derive 0.1.0

Derive macros for the nami reactive framework
Documentation

nami-derive

Derive macros for the nami reactive framework.

This crate provides procedural derive macros that automatically implement traits for the nami reactive system, making it easier to work with complex data structures in reactive applications.

Features

  • #[derive(Project)] - Automatically implement the Project trait for structs, enabling decomposition into individual field bindings

Usage

Add this to your Cargo.toml:

[dependencies]
nami = { version = "0.1", features = ["derive"] }

The derive macros are re-exported through the main nami crate when the derive feature is enabled (which is the default).

#[derive(Project)]

The Project derive macro automatically generates implementations that allow you to decompose struct bindings into separate bindings for each field.

Named Structs

For structs with named fields, the macro generates a corresponding "projected" struct where each field is wrapped in a Binding:

use nami::{Binding, binding};

#[derive(nami::Project)]
struct Person {
    name: String,
    age: u32,
    email: String,
}

let person = binding(Person {
    name: "Alice".to_string(),
    age: 30,
    email: "alice@example.com".to_string(),
});

// Project into individual field bindings
let projected = person.project();

// Access and modify individual fields
projected.name.set("Bob".to_string());
projected.age.set(25);

// Changes are reflected in the original binding
let updated_person = person.get();
assert_eq!(updated_person.name, "Bob");
assert_eq!(updated_person.age, 25);
assert_eq!(updated_person.email, "alice@example.com"); // unchanged

Tuple Structs

For tuple structs, the macro generates a tuple of bindings:

use nami::{Binding, binding};

#[derive(nami::Project)]
struct Point(i32, i32);

let point = binding(Point(10, 20));
let (x, y) = point.project();

x.set(100);
y.set(200);

assert_eq!(point.get().0, 100);
assert_eq!(point.get().1, 200);

Unit Structs

Unit structs project to the unit type ():

use nami::{Binding, binding};

#[derive(nami::Project)]
struct Marker;

let marker = binding(Marker);
let _unit = marker.project(); // Returns ()

Generic Types

The derive macro supports generic types with appropriate lifetime bounds:

use nami::{Binding, binding};

#[derive(nami::Project)]
struct Container<T> {
    value: T,
    count: usize,
}

let container = binding(Container {
    value: "hello",
    count: 5,
});

let projected = container.project();
projected.value.set("world");
projected.count.set(10);

Bidirectional Reactivity

All projected bindings maintain bidirectional reactivity with the original binding:

  • Changes to projected bindings update the corresponding field in the original
  • Changes to the original binding are reflected in the projected bindings
  • The reactive system ensures efficient updates and notifications

Limitations

  • The derive macro only supports structs (not enums or unions)
  • All field types must implement Clone and have 'static lifetime
  • Generic parameters automatically get 'static bounds added

License

This project is licensed under the MIT License - see the LICENSE file for details.