const std = @import("std"); const matcha = @import("root.zig"); const Cmd = matcha.Cmd; const Msg = matcha.Msg; const View = matcha.View; const Allocator = std.mem.Allocator; const Writer = std.Io.Writer; const Model = @This(); vtable: *const VTable, /// Long-lived program allocator. Set by Program before any callback runs. /// Use for state that lives across updates (ArrayLists, HashMaps, etc.). /// Equivalent to `process.gpa` — published flat for ergonomics. gpa: Allocator = undefined, /// Per-callback scratch arena. Reset by Program before every callback /// (init/update/view) — allocations are valid only until the callback /// returns. Never store an arena-backed pointer on the model. arena: Allocator = undefined, /// `std.Io` handle, useful for blocking file/process work driven from /// `init`/`update`. Set by Program before any callback runs. /// Equivalent to `process.io` — published flat for ergonomics. io: std.Io = undefined, /// Full process bundle (env vars, argv, preopens, process-permanent arena). /// Set by Program before any callback runs. Use `process.environ_map.get(...)` /// for env lookups, `process.minimal.args` for argv, etc. process: std.process.Init = undefined, pub const VTable = struct { /// Called once at program start. May return an initial Cmd. init: *const fn (model: *Model) ?Cmd, /// Called for every Msg. May return a follow-up Cmd. update: *const fn (model: *Model, msg: Msg) ?Cmd, /// Render the current frame. Bytes are written to `w` (a program-owned /// buffer that's reset before each call); the returned `View` carries /// the rest of the frame's metadata. The writer is only valid for the /// duration of this call. view: *const fn (model: *Model, w: *Writer) Writer.Error!View, }; pub fn init(self: *Model) ?Cmd { return self.vtable.init(self); } pub fn update(self: *Model, msg: Msg) ?Cmd { return self.vtable.update(self, msg); } pub fn view(self: *Model, w: *Writer) Writer.Error!View { return self.vtable.view(self, w); }