Skip to main content

Module codegen

Module codegen 

Source
Expand description

A form file, as Rust the compiler checks.

The engine hands back built.node("who") and resolves message names through a match on a string. That is right for a kiosk, it is checked when the form loads, and it is what Form::build does. What it is not is what Delphi gave you, which was Button1: TButton as a field the compiler knew about.

This generates that. Point a build.rs at a form file and get a struct whose fields are the form’s named nodes and an enum whose variants are the form’s messages:

// build.rs
fn main() {
    denise_forms::codegen::to_out_dir("forms/settings.dform").unwrap();
}
// src/main.rs
include!(concat!(env!("OUT_DIR"), "/settings.rs"));

let form = Settings::build(&mut ui, root)?;
ui.widget_mut::<TextInput<SettingsMessage>>(form.who);   // a field, not a lookup

Rename a node in the form and the application stops compiling, naming the field that no longer exists. Add a message to the form and every match on the enum stops compiling, because it is no longer exhaustive. Both are the point, and both are what a string lookup cannot do.

And a trait, SettingsHandlers, with one method per message named for it — fn save(&mut self), fn set_notify(&mut self, on: bool) — plus SettingsMessage::dispatch, which calls the method a message is named for. Implement the trait for whatever handles the form and there is no match to write at all: add an event in the designer and the compiler names the method that is missing, which is the one the designer writes when asked to open it.

§A build script rather than a proc macro

Chosen deliberately, and #101 said to. The output is a file you can open, cargo doc sees it, a debugger steps through it, and it needs no second crate. A macro would read a little better at the call site and cost all four.

§It generates a caller, not a second engine

The generated build calls Form::build with a generated Wiring. There is one implementation of building a form, and this is a typed door onto it — so a form that loads at runtime and the same form generated behave identically, because they are the same code.

Structs§

Generated
What one form generated: the text of a module, and what is in it.

Functions§

generate
Generates the struct and the enum for a form.
to_out_dir
Generates a form into OUT_DIR and tells Cargo to watch it.