| 5521 | const succeedFalse = succeed(false) |
| 5522 | |
| 5523 | class Latch implements _Latch.Latch { |
| 5524 | waiters: Array<(_: Effect.Effect<void>) => void> = [] |
| 5525 | scheduled: Array<(_: Effect.Effect<void>) => void> | undefined = undefined |
| 5526 | private _isOpen: boolean |
| 5527 | |
| 5528 | constructor(isOpen: boolean) { |
| 5529 | this._isOpen = isOpen |
| 5530 | } |
| 5531 | |
| 5532 | private scheduleUnsafe(fiber: Fiber.Fiber<unknown, unknown>) { |
| 5533 | if (this.waiters.length === 0) { |
| 5534 | return succeedTrue |
| 5535 | } |
| 5536 | if (this.scheduled === undefined) { |
| 5537 | this.scheduled = this.waiters |
| 5538 | fiber.currentDispatcher.scheduleTask(this.flushScheduled, 0) |
| 5539 | } else { |
| 5540 | for (let i = 0; i < this.waiters.length; i++) { |
| 5541 | this.scheduled.push(this.waiters[i]) |
| 5542 | } |
| 5543 | } |
| 5544 | this.waiters = [] |
| 5545 | return succeedTrue |
| 5546 | } |
| 5547 | private flushScheduled = () => { |
| 5548 | if (this.scheduled === undefined) return |
| 5549 | const waiters = this.scheduled |
| 5550 | this.scheduled = undefined |
| 5551 | for (let i = 0; i < waiters.length; i++) { |
| 5552 | waiters[i](exitVoid) |
| 5553 | } |
| 5554 | } |
| 5555 | private flushWaiters() { |
| 5556 | // swap both arrays out before any resume runs: a resumed waiter can |
| 5557 | // reentrantly close the latch and register new waiters, which must not |
| 5558 | // be drained by this flush |
| 5559 | const waiters = this.waiters |
| 5560 | this.waiters = [] |
| 5561 | this.flushScheduled() |
| 5562 | for (let i = 0; i < waiters.length; i++) { |
| 5563 | waiters[i](exitVoid) |
| 5564 | } |
| 5565 | } |
| 5566 | |
| 5567 | open = withFiber<boolean>((fiber) => { |
| 5568 | if (this._isOpen) return succeedFalse |
| 5569 | this._isOpen = true |
| 5570 | return this.scheduleUnsafe(fiber) |
| 5571 | }) |
| 5572 | release = withFiber<boolean>((fiber) => this._isOpen ? succeedFalse : this.scheduleUnsafe(fiber)) |
| 5573 | openUnsafe() { |
| 5574 | if (this._isOpen) return false |
| 5575 | this._isOpen = true |
| 5576 | this.flushWaiters() |
| 5577 | return true |
| 5578 | } |
| 5579 | await = callback<void>((resume) => { |
| 5580 | if (this._isOpen) { |
nothing calls this directly
no test coverage detected