I redesigned the representation of the state machine on the type and allowed the existence of recursive types.
This is a huge improvement.
Here is an example of Atm, I can limit the number of checkPin times to not exceed 3 times. Actually I just need to implement a general handling function for checkPin state, and then I just need to express this constraint on the type. Then all interactions will be completed automatically, you will get an interface to input pins and try it up to 3 times.
code
pub const readyST = union(enum) {
InsertCard: EWitFn(.{ Atm.checkPin, Atm.session, .{ Atm.checkPin, Atm.session, .{ Atm.checkPin, Atm.session, Atm.ready } } }),
Exit: EWit(.exit),
pub fn handler(ist: *State) void {
switch (genMsg(ist.window)) {
.Exit => |wit| wit.handler(ist),
.InsertCard => |wit| wit.handler(ist),
}
}
.....
pub fn checkPinST(success: typedFsm.sdzx(Atm), failed: typedFsm.sdzx(Atm)) type {
return union(enum) {
Successed: typedFsm.Witness(Atm, success, State, prinet_enter_state),
Failed: typedFsm.Witness(Atm, failed, State, prinet_enter_state),
pub fn handler(ist: *State) void {
switch (genMsg(ist.window, &ist.pin)) {
.Successed => |wit| wit.handler(ist),
.Failed => |wit| wit.handler(ist),
}
}
fn genMsg(window: *Window, pin: []const u8) @This() {
var tmpPin: [4:0]u8 = .{ 0, 0, 0, 0 };
while (true) {
init(window);
defer {
zgui.backend.draw();
window.swapBuffers();
}
{
_ = zgui.begin("CheckPin", .{ .flags = .{
.no_collapse = true,
.no_move = true,
.no_resize = true,
} });
defer zgui.end();
_ = zgui.inputText("pin", .{
.buf = &tmpPin,
.flags = .{ .password = true, .chars_decimal = true },
});
if (zgui.button("OK", .{})) {
for (0..4) |i| tmpPin[i] -|= 48;
if (std.mem.eql(u8, &tmpPin, pin)) {
return .Successed;
} else {
return .Failed;
}
}
}
}
}
};
}
It’s really interesting combination. Type combination brings the combination of front-end and back-end.