(key: K, permits: number)
| 84 | const partitions = MutableHashMap.empty<K, Set<Waiter>>() |
| 85 | |
| 86 | const take = (key: K, permits: number) => |
| 87 | Effect.async<void>((resume) => { |
| 88 | if (maxPermits < permits) { |
| 89 | return resume(Effect.never) |
| 90 | } else if (totalPermits >= permits) { |
| 91 | totalPermits -= permits |
| 92 | return resume(Effect.void) |
| 93 | } |
| 94 | |
| 95 | const needed = permits - totalPermits |
| 96 | const taken = permits - needed |
| 97 | if (totalPermits > 0) { |
| 98 | totalPermits = 0 |
| 99 | } |
| 100 | waitingPermits += needed |
| 101 | |
| 102 | const waiters = Option.getOrElse( |
| 103 | MutableHashMap.get(partitions, key), |
| 104 | () => { |
| 105 | const set = new Set<Waiter>() |
| 106 | MutableHashMap.set(partitions, key, set) |
| 107 | return set |
| 108 | } |
| 109 | ) |
| 110 | |
| 111 | const entry: Waiter = { |
| 112 | permits: needed, |
| 113 | resume() { |
| 114 | cleanup() |
| 115 | resume(Effect.void) |
| 116 | } |
| 117 | } |
| 118 | function cleanup() { |
| 119 | waiters.delete(entry) |
| 120 | if (waiters.size === 0) { |
| 121 | MutableHashMap.remove(partitions, key) |
| 122 | } |
| 123 | } |
| 124 | waiters.add(entry) |
| 125 | return Effect.sync(() => { |
| 126 | cleanup() |
| 127 | waitingPermits -= entry.permits |
| 128 | if (taken > 0) { |
| 129 | releaseUnsafe(taken) |
| 130 | } |
| 131 | }) |
| 132 | }) |
| 133 | |
| 134 | let iterator = partitions[Symbol.iterator]() |
| 135 | const releaseUnsafe = (permits: number) => { |
no test coverage detected