waterui-macros
Procedural macros for the WaterUI framework, providing automatic derive implementations and code generation for forms, reactive projections, string formatting, and hot reload functionality.
Overview
This crate is the macro engine behind WaterUI's ergonomic APIs. It provides four main categories of macros:
- Form Generation - Automatically generate UI forms from Rust structs with
#[derive(FormBuilder)]and#[form] - Reactive Projections - Decompose struct bindings into per-field bindings with
#[derive(Project)] - Formatted Strings - Create reactive formatted strings with the
s!macro - Hot Reload - Enable per-function hot reloading with
#[hot_reload]
This crate is typically accessed through the main waterui crate via use waterui::prelude::*; rather than being used directly.
Installation
Add to your Cargo.toml:
[]
= "0.2"
The derive macros are automatically available when you import the prelude:
use *;
Core Macros
Form Builder System
#[derive(FormBuilder)]
Automatically implements the FormBuilder trait for structs, generating form UI components based on field types.
Type-to-Component Mapping:
| Rust Type | UI Component | Description |
|---|---|---|
String, Str |
TextField |
Text input with optional placeholder |
bool |
Toggle |
Boolean switch/checkbox |
i8..isize, u8..usize |
Stepper |
Numeric stepper with increment/decrement |
f32, f64 |
Slider |
Slider (0.0-1.0 range) |
Color |
ColorPicker |
Color selection widget |
Example from /Users/lexoliu/Coding/waterui/examples/form/src/lib.rs:
use *;
use binding;
How it works:
- Converts
snake_casefield names to "Title Case" labels (e.g.,full_name→ "Full Name") - Uses doc comments as placeholder text for text fields
- Automatically calls
Project::project()on the binding to access individual fields - Returns a
VStackcontaining all generated form controls
#[form]
Convenience attribute macro that combines multiple common derives for form structs.
Equivalent to:
Example from /Users/lexoliu/Coding/waterui/examples/form/src/lib.rs:
Reactive Projection
#[derive(Project)]
Implements the Project trait, enabling decomposition of struct bindings into separate bindings for each field. This is essential for reactive form handling where each field needs independent mutation.
Supports:
- Named structs
- Tuple structs
- Unit structs
Example from /Users/lexoliu/Coding/waterui/derive/src/lib.rs documentation:
use ;
use Project;
let person_binding: = binding;
let projected = person_binding.project;
projected.name.set;
projected.age.set;
let person = person_binding.get;
assert_eq!;
assert_eq!;
Generated code:
For a struct MyForm, the macro generates:
- A
MyFormProjectedstruct with each field wrapped inBinding<T> - A
Projectimplementation that creates mapped bindings for each field - Proper lifetime bounds (
'static) on generic parameters
String Formatting
s! - Reactive String Formatting
Function-like procedural macro for creating formatted string signals with automatic variable capture. Powers the text! macro in WaterUI.
Features:
- Automatic variable capture from format string placeholders
- Positional and named argument support
- Reactive updates when dependencies change
- Supports up to 4 variables/arguments
Usage patterns:
use ;
use s;
let name = binding;
let age = binding;
// Named variable capture (automatic)
let msg = s!;
// Positional arguments
let msg2 = s!;
// Static strings (returns constant signal)
let static_msg = s!;
Used internally by text! macro:
// From /Users/lexoliu/Coding/waterui/src/lib.rs
Implementation details:
- Uses
zipcombinator to merge multiple reactive signals - Delegates to
__format!macro for actual formatting - Returns
Computed<Str>for reactive values,Constant<Str>for static strings - Validates format string at compile time (detects mismatched argument counts)
Hot Reload
#[hot_reload]
Attribute macro that enables per-function hot reloading during development. When the library is rebuilt via water run, only the annotated function is updated without restarting the app.
Example from /Users/lexoliu/Coding/waterui/src/debug/hot_reload.rs documentation:
use *;
How it works:
- Wraps the function body in a
HotReloadViewthat registers with the hot reload system - Generates a C-exported symbol (when built with
--cfg waterui_hot_reload_lib):pub unsafe extern "C" - The CLI loads this symbol from the rebuilt dylib and updates all registered handlers
- Uses
module_path!()+ function name as unique identifier (e.g.,"my_crate::sidebar")
Requirements:
- Function must return
impl View - Enable hot reload with
WATERUI_HOT_RELOAD_HOSTandWATERUI_HOT_RELOAD_PORTenvironment variables (set bywater run) - Build hot reload library with
RUSTFLAGS="--cfg waterui_hot_reload_lib" cargo build
API Overview
Derive Macros
FormBuilder- Generate form UI from struct definitionProject- Enable field-level reactive bindings
Attribute Macros
#[form]- Convenience macro for form structs (combines multiple derives)#[hot_reload]- Enable per-function hot reloading
Function-like Macros
s!(...)- Create reactive formatted strings with automatic variable capture
Features
This is a proc-macro crate with no optional features. All macros are always available.
Implementation Notes
- Rust Edition: 2024
- Dependencies:
syn ^2.0,quote ^1.0,proc-macro2 ^1.0 - Workspace Integration: Part of the WaterUI workspace, follows workspace lints (clippy pedantic + nursery)
Compile-Time Validation
The macros perform extensive compile-time validation:
FormBuilder: Requires named struct fieldss!: Detects mismatched placeholder/argument counts, mixed positional/named usageProject: Rejects enums and unions (only works with structs)form: Requires structs with named fields
Code Generation Strategy
Form Builder:
- Generates type-safe view types using the builder pattern
- Uses
Quote::quote!for generating trait implementations - Automatically handles
Projecttrait bounds for field access
Project:
- Creates a parallel struct with
Projectedsuffix - Uses
Binding::mappingfor bidirectional field synchronization - Adds
'staticbounds to generic parameters
String Formatting:
- Analyzes format strings with custom parser
- Generates optimized code paths for 0-4 variables
- Uses nested
zipcalls for multiple signal combination
Development
To test changes to the macros:
# Run tests (uses waterui as dev-dependency)
# Check macro expansion
# Test in a real project
# Add #[form] to a struct and run