Definitions

Waltzing templates can define Rust structs, enums, and functions that are compiled into the generated code.

@struct

Define Rust structs within templates:

Basic Struct

@struct User {
    name: String,
    email: String,
    age: u32,
}

With Derive Attributes

Add derive macros using bracket syntax:

@struct[derive(Debug, Clone, Serialize, Deserialize)] User {
    name: String,
    email: String,
    active: bool,
}

@struct[derive(Default, PartialEq)] Config {
    debug: bool,
    max_items: usize,
}

With Field Attributes

Add attributes to individual fields:

@struct[derive(Serialize, Deserialize)] ApiRequest {
    user_id: u64,
    query[serde(rename = "q")]: String,
    limit[serde(default)]: Option,
    secret[serde(skip_serializing)]: String,
}

@struct[derive(Deserialize)] FormData {
    username: String,
    password[serde(skip_serializing)]: String,
    remember[serde(default = "default_false")]: bool,
}

With Generics

@struct[derive(Clone)] Container {
    items: Vec,
    count: usize,
}

@struct[derive(Debug)] Result {
    data: Option,
    error: Option,
}

With Lifetimes

@struct[derive(Debug)] BorrowedData<'a> {
    name: &'a str,
    items: &'a [Item],
}
Default Derives

By default, structs automatically derive Debug, Clone, and serde::Deserialize. Disable with feature flags in Cargo.toml.

@enum

Define Rust enums within templates:

Basic Enum

@enum Status {
    Active,
    Inactive,
    Pending,
}

With Data

@enum Message {
    Text(String),
    Number(i64),
    Pair(String, i32),
}

@enum ApiResult {
    Success { data: String, count: u32 },
    Error { code: u16, message: String },
    Empty,
}

With Derive Attributes

@enum[derive(Debug, Clone, Serialize, PartialEq)] UserRole {
    Admin,
    Moderator,
    User,
    Guest,
}

@enum[derive(Deserialize)] Action {
    Create { name: String },
    Update { id: u64, data: String },
    Delete { id: u64 },
}

With Variant Attributes

@enum[derive(Serialize, Deserialize)] Event {
    Click[serde(rename = "click")] { x: i32, y: i32 },
    KeyPress[serde(rename = "keypress")] { key: String },
    Scroll[serde(rename = "scroll")] { delta: i32 },
}

@fn (Template Functions)

Define template functions (see Components for full details):

Basic Function

@fn greet(name: String) {
    

Hello, @name!

}

With Default Parameters

@fn button(
    label: String,
    variant: String = "primary",
    disabled: bool = false,
) {
    
}

With Generic Parameters

@fn list(items: &[T], class: String = "list") {
    
    @for item in items {
  • @item
  • }
}

With Function Parameters

Pass functions as parameters for custom rendering:

@fn data_table(
    items: &[T],
    render_row: fn(&T) -> String,
    empty_message: String = "No items",
) {
    
            @if items.is_empty() {
                
            } else {
                @for item in items {
                    @safe((render_row)(item))
                }
            }
        
@empty_message
} @* Usage *@ @data_table(users, |u| format!("{}{}", u.name, u.email))

With Closure Parameters

@fn map_items(items: &[T], mapper: F)
where
    F: Fn(&T) -> String,
{
    @for item in items {
        @safe((mapper)(item))
    }
}

@use (Imports)

Import Rust types from your crate:

@use crate::models::User
@use crate::models::{Post, Comment}
@use std::collections::HashMap
@use crate::helpers::format_date

@import (Template Imports)

Import other templates:

@import "layouts/base.wtz" as layout
@import "components/button.wtz" as button
@import "components/card.wtz" as card

@fn apply(data: PageData) {
    <@layout title="Home">
        <@card title="Welcome">
            <@button label="Click me" />
        
    
}