import { Tag , defineTag } from "@esfx/internal-tag" ; import { AsyncLockable , LockHandle } from "@esfx/async-lockable" ; import { WaitQueue } from "@esfx/async-waitqueue" ; import { Cancelable } from "@esfx/cancelable" ; import { Disposable } from "@esfx/disposable" ; /**
 * An async coordination primitive used to coordinate access to a protected resource.
 */ @ Tag ( ) export class AsyncMutex implements AsyncLockable { private _waiters = new WaitQueue < void > ( ) ; private _handle : LockHandle < AsyncMutex > | undefined ; /**
     * Indicates whether the lock has been taken.
     */ get isLocked ( ) { return this . _handle !== undefined ; } param cancelable async lock ( cancelable ? ) { const handle = createLockHandle ( this ) ; await handle . lock ( cancelable ) ; return handle ; } /**
     * Synchronously tries to take a lock.
     */ tryLock ( ) { if ( ! this . _handle ) { this . _handle = createLockHandle ( this ) ; return true ; } return false ; } /**
     * Releases the lock.
     */ unlock ( ) { if ( this . _handle ) { this . _unlock ( this . _handle ) ; return true ; } return false ; } private async _lock ( handle , cancelable ? ) { Cancelable . throwIfSignaled ( cancelable ) ; if ( this . _handle === handle ) { throw new Error ( "Lock already taken." ) ; } if ( this . _handle ) { await this . _waiters . wait ( cancelable ) ; if ( this . _handle === handle ) { throw new Error ( "Lock already taken." ) ; } } this . _handle = handle ; } private _unlock ( handle ) { if ( this . _handle !== handle ) { throw new Error ( "Lock already released." ) ; } if ( ! this . _waiters . resolveOne ( ) ) { this . _handle = undefined ; } } [ AsyncLockable . lock ] ( cancelable ? ) { return this . lock ( cancelable ) ; } [ AsyncLockable . unlock ] ( ) { this . unlock ( ) ; } } const mutexLockHandlePrototype = { [ AsyncLockable . lock ] ( this , cancelable ? ) { return this . lock ( cancelable ) ; } , [ AsyncLockable . unlock ] ( this ) { return this . unlock ( ) ; } , [ Disposable . dispose ] ( this ) { if ( this . ownsLock ) { this . unlock ( ) ; } } } ; defineTag ( mutexLockHandlePrototype , "MutexLockHandle" ) ; Object . setPrototypeOf ( mutexLockHandlePrototype , Disposable . prototype ) ; function createLockHandle ( mutex ) { const handle = Object . setPrototypeOf ( { get mutex ( ) { return mutex ; } , get ownsLock ( ) { return mutex [ "_handle" ] === handle ; } , async lock ( cancelable ? ) { await mutex [ "_lock" ] ( handle , cancelable ) ; return this ; } , unlock ( ) { mutex [ "_unlock" ] ( handle ) ; } } , mutexLockHandlePrototype ) ; return handle ; }