I didn’t think I was entering unexplored territory… for context, here’s how I was envisioning it being used:
struct SteppingClock: AlarmClock {
struct Instant: Hashable, Equatable {
var tick: Int
func duration(to other: Instant) -> Int { other.tick - tick }
func advanced(by duration: Int) -> Instant { Instant(tick: tick + duration) }
static func==(lhs: Instant, rhs: Instant) -> Bool { lhs.tick == rhs.tick }
}
private var alarms: [Instant: [(SteppingClock) -> Void]]
public private(set) var now: Instant
func alarm(at: Instant, body: @concurrent (clock: SteppingClock) -> Void) {
// body must be responsible for switching to the appropriate executor.
// obv. this won’t compile as a nonmutating func; imagine thread-safe, out of line storage for alarms.
var newAlarms = alarms[at] ?? []
newAlarms.append(body)
alarms[at] = newAlarms
}
mutating func step() {
now = now.advanced(by: 1)
for alarm in alarms[now] ?? [] {
alarm(self)
}
}
}