// One latest target in a core shared row. Versions are snapshot tokens, not a // sample count. The producer never touches the consumer's acknowledgement. export class Mailbox { constructor({ buffer, descriptor }) { this.words = new Int32Array(buffer, descriptor.offset, 16); this.scratch = new ArrayBuffer(4); this.bits = new Int32Array(this.scratch); this.float = new Float32Array(this.scratch); } encode(value) { this.float[0] = value; return this.bits[0]; } decode(value) { this.bits[0] = value; return this.float[0]; } write(stroke, sample, seed) { const version = (Atomics.load(this.words, 0) + 2) | 0; Atomics.store(this.words, 0, version - 1); Atomics.store(this.words, 2, stroke); Atomics.store(this.words, 3, this.encode(sample.x)); Atomics.store(this.words, 4, this.encode(sample.y)); Atomics.store(this.words, 5, this.encode(sample.pressure)); Atomics.store(this.words, 6, this.encode(seed ?? 0)); Atomics.store(this.words, 7, seed === undefined ? 0 : 1); Atomics.store(this.words, 0, version); return version; } read(stroke) { const a = Atomics.load(this.words, 0); if (a & 1 || a === Atomics.load(this.words, 1)) return null; const id = Atomics.load(this.words, 2); const x = this.decode(Atomics.load(this.words, 3)); const y = this.decode(Atomics.load(this.words, 4)); const pressure = this.decode(Atomics.load(this.words, 5)); const seed = this.decode(Atomics.load(this.words, 6)); const hasSeed = Atomics.load(this.words, 7); if (a !== Atomics.load(this.words, 0) || id !== stroke) return null; return { version: a, x, y, pressure, seed: hasSeed ? seed : undefined }; } acknowledge(version) { Atomics.store(this.words, 1, version); } get processed() { return Atomics.load(this.words, 1); } }