export class Lock {

    constructor () {
        /** @member {boolean} */
        this.isLocked = false;

        /** @member Function[] */
        this.queue = [];
    }

    async acquire() {
        if (!this.isLocked) {
            this.isLocked = true;
            return;
        }

        await new Promise(resolve => {
            this.queue.push(resolve);
        });
    }

    release() {
        this.isLocked = false;
        if (this.queue.length === 0) {
            return;
        }

        const next = this.queue.splice(0, 1)[0];
        next();
    }

    async lock(callback) {
        await this.acquire();

        const resultOrPromise = callback();
        const result = (resultOrPromise instanceof Promise) ? (await resultOrPromise) : resultOrPromise;

        this.release();
        return result;
    }

}
