module.exports = class Sequester {
constructor () {
this._queue = [{ exclusive: false, count: 0, promise: null, resolve: null }]
}
get mutexes () {
return this._queue.map(mutex => mutex.count)
}
get state () {
return this._queue[0].exclusive ? 'exclusive' : 'shared'
}
increment (count) {
this._queue[0].count += count
}
share () {
if (this._queue.length == 1) {
this._queue[0].count++
return null
}
const shared = this._queue[this._queue.length - 1]
shared.count++
return shared.promise
}
exclude () {
const exclusive = {
exclusive: true,
count: 1,
promise: this._queue.length == 1 && this._queue[0].count == 0
? null
: new Promise(resolve => this._queue[this._queue.length - 1].resolve = resolve),
resolve: null
}
const shared = {
exclusive: false,
count: 0,
upgradable: false,
promise: new Promise(resolve => exclusive.resolve = resolve),
resolve: null
}
this._queue.push(exclusive, shared)
if (exclusive.promise == null) {
this._queue.shift()
}
return exclusive.promise
}
downgrade () {
this._queue[1].count++
this.unlock()
}
unlock () {
this._queue[0].count--
while (this._queue.length != 1 && this._queue[0].count == 0) {
this._queue.shift().resolve.call()
}
}
}