import { Deferred } from './Deferred';

const deferredMap = new WeakMap();

/**
 * Creates a deferred lock on the given object in order to sync critical blocks with race conditions.
 * Usage:
 *  releaseLock = await requestLock(obj);
 *  // do the critical actions in between
 *  releaseLock(); // important: always call this at the end of the critical block
 * Since it has to be used with the await keyword, it can guarantee that the block after the await requestLock(obj)
 * will be executed only if the concurrent lock was released.
 * @param object
 * @return {Promise<function(): *>}
 */
export const requestLock = object => {
    const deferred = new Deferred();
    const prev = deferredMap.get(object);
    deferredMap.set(object, deferred);
    return new Promise(resolve => {
        if (prev) {
            prev.then(() => {
                resolve(deferred.resolve);
            });
        } else {
            resolve(deferred.resolve);
        }
    });
};
