tiny.game.settle
Defined in tiny.game.
A detector that reports a change to a file once the file has held still for a window of time.
API (4)
Actions
Public operations.
Settle.observe: Records one look at the file and returns true when a change has held still forwindow_nssince the look that saw it.Stamp.eql: Returns true when both the modification time and the size match.
Types and contracts
Public types and contracts.
Settle: The state of one change detector: the last stamp it saw and, while a change waits, the time at which it may report that change.Stamp: A file's modification time and size, taken at one look.
Source
Source: fun/game/src/root.zig:120
zig
pub const settle = @import("settle.zig");Source: fun/game/src/settle.zig
zig
//! A detector that reports a change to a file once the file has held still for a window of time.//!//! A host that reloads code after a rebuild wants to act on each rebuild once, as soon as the new//! file is complete. A compiler writes a library file over a stretch of time, and the file's size//! can change more than once during one write, so a host that acts on the first change can load a//! half-written file.//!//! At each look the caller hands the detector the file's modification time and size at that look (a//! *stamp*) and the current time, so the detector reads no clock and no file of its own. A stamp//! that differs from the last one starts a window at the current time, and a later look with the//! same stamp at or past the window's end reports the change. A change seen while an earlier one//! waits starts the window again. The detector reports each change a single time, and then waits//! for the next change. The detector's first look records a baseline and reports nothing.const std = @import("std");/// A file's modification time and size, taken at one look. A caller builds one from each look at/// the file and passes it to `Settle.observe`.pub const Stamp = struct { /// The file's modification time in nanoseconds, as the file system reports it. mtime_ns: i128, /// The file's size in bytes. size: u64, /// Returns true when both the modification time and the size match. `Settle.observe` tells with /// it whether the file changed since the last look. pub fn eql(a: Stamp, b: Stamp) bool { return a.mtime_ns == b.mtime_ns and a.size == b.size; }};/// The state of one change detector: the last stamp it saw and, while a change waits, the time at/// which it may report that change. A reloader keeps one for the file it watches and hands it a/// stamp at each poll. A detector starts empty, as `Settle{}`, and its first look records a/// baseline.pub const Settle = struct { seen: ?Stamp = null, fire_at: ?i128 = null, /// Records one look at the file and returns true when a change has held still for `window_ns` /// since the look that saw it. A caller looks at the file on its own schedule and acts on the /// change when the call returns true. The first call records `stamp` as a baseline and returns /// false. A stamp that differs from the last one is recorded, starts the window at `now_ns`, /// and returns false. The same stamp returns false before the window's end and true at the /// first look at or past it. After a true result, the call returns false until the stamp /// changes again and a new window ends. The call reports only at a look, so a caller that looks /// less often than the window hears of the change at its next look. pub fn observe(self: *Settle, stamp: Stamp, now_ns: i128, window_ns: i128) bool { const seen = self.seen orelse { self.seen = stamp; return false; }; if (!seen.eql(stamp)) { self.seen = stamp; self.fire_at = now_ns + window_ns; return false; } const deadline = self.fire_at orelse return false; if (now_ns < deadline) return false; self.fire_at = null; return true; }};const window: i128 = 100;test "the first observation is a baseline that never fires" { var settle = Settle{}; try std.testing.expect(!settle.observe(.{ .mtime_ns = 5, .size = 10 }, 0, window)); try std.testing.expect(!settle.observe(.{ .mtime_ns = 5, .size = 10 }, 1_000, window));}test "a settled change fires once after the window elapses" { var settle = Settle{}; _ = settle.observe(.{ .mtime_ns = 5, .size = 10 }, 0, window); try std.testing.expect(!settle.observe(.{ .mtime_ns = 6, .size = 12 }, 10, window)); try std.testing.expect(!settle.observe(.{ .mtime_ns = 6, .size = 12 }, 50, window)); try std.testing.expect(settle.observe(.{ .mtime_ns = 6, .size = 12 }, 110, window)); try std.testing.expect(!settle.observe(.{ .mtime_ns = 6, .size = 12 }, 200, window));}test "an unsettled file keeps re-arming and does not fire mid-write" { var settle = Settle{}; _ = settle.observe(.{ .mtime_ns = 5, .size = 10 }, 0, window); try std.testing.expect(!settle.observe(.{ .mtime_ns = 6, .size = 12 }, 10, window)); try std.testing.expect(!settle.observe(.{ .mtime_ns = 6, .size = 40 }, 80, window)); try std.testing.expect(!settle.observe(.{ .mtime_ns = 6, .size = 99 }, 130, window)); try std.testing.expect(!settle.observe(.{ .mtime_ns = 6, .size = 99 }, 200, window)); try std.testing.expect(settle.observe(.{ .mtime_ns = 6, .size = 99 }, 240, window));}test "a second change after a fire arms again" { var settle = Settle{}; _ = settle.observe(.{ .mtime_ns = 5, .size = 10 }, 0, window); _ = settle.observe(.{ .mtime_ns = 6, .size = 12 }, 10, window); try std.testing.expect(settle.observe(.{ .mtime_ns = 6, .size = 12 }, 120, window)); try std.testing.expect(!settle.observe(.{ .mtime_ns = 7, .size = 14 }, 130, window)); try std.testing.expect(settle.observe(.{ .mtime_ns = 7, .size = 14 }, 240, window));}Audit
| Definitions | 5 |
|---|---|
| Public names | 5 |
| Members | 4 |
| Version | 26.7.0 |
| Revision | daab053ee433 |