src/permit-pool.tsTypeScript
@@ -0,0 +1,43 @@
1+
export type ReleasePermit = () => void;2+
3+
export class PermitPool {4+
private available: number;5+
private readonly waiters: Array<(release: ReleasePermit) => void> = [];6+
7+
constructor(capacity: number) {8+
if (!Number.isInteger(capacity) || capacity < 1) {9+
throw new RangeError("capacity must be a positive integer");10+
}11+
12+
this.available = capacity;13+
}14+
15+
acquire(): Promise<ReleasePermit> {16+
if (this.available > 0) {17+
this.available -= 1;18+
return Promise.resolve(this.createRelease());19+
}20+
21+
return new Promise((resolve) => {22+
this.waiters.push(resolve);23+
});24+
}25+
26+
private createRelease(): ReleasePermit {27+
let released = false;28+
29+
return () => {30+
if (released) {31+
throw new Error("permit released twice");32+
}33+
released = true;34+
35+
const next = this.waiters.shift();36+
if (next) {37+
next(this.createRelease());38+
} else {39+
this.available += 1;40+
}41+
};42+
}43+
}