@dxos/async 0.3.11-next.0fb359e → 0.3.11-next.e28df4f

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -14,7 +14,7 @@
14
14
  * Java docs reference on synchronized sections:
15
15
  * https://docs.oracle.com/javase/tutorial/essential/concurrency/locksync.html
16
16
  */
17
- export declare class Lock {
17
+ export declare class Mutex {
18
18
  private _queue;
19
19
  private _tag;
20
20
  get tag(): string | null;
@@ -24,7 +24,7 @@ export declare class Lock {
24
24
  * NOTE: Using `executeSynchronized` is preferred over using `acquire` directly.
25
25
  * @returns Release callback
26
26
  */
27
- acquire(tag?: string): Promise<() => void>;
27
+ acquire(tag?: string): Promise<MutexGuard>;
28
28
  /**
29
29
  * Waits for all previous executions to complete and then executes a given function.
30
30
  * Only a single function can be executed at a time.
@@ -33,10 +33,19 @@ export declare class Lock {
33
33
  */
34
34
  executeSynchronized<T>(fun: () => Promise<T>): Promise<T>;
35
35
  }
36
+ export declare class MutexGuard {
37
+ private readonly _release;
38
+ constructor(_release: () => void);
39
+ /**
40
+ * Releases the lock.
41
+ */
42
+ release(): void;
43
+ [Symbol.dispose](): void;
44
+ }
36
45
  /**
37
46
  * Same as `synchronized` in Java.
38
47
  * Uses a lock global to the current class instance.
39
48
  * This way every synchronized method on the same instance will share a single lock.
40
49
  */
41
50
  export declare const synchronized: (target: any, propertyName: string, descriptor: TypedPropertyDescriptor<(...args: any) => any>) => void;
42
- //# sourceMappingURL=lock.d.ts.map
51
+ //# sourceMappingURL=mutex.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mutex.d.ts","sourceRoot":"","sources":["../../../src/mutex.ts"],"names":[],"mappings":"AAMA;;;;;;;;;;;;;;;GAeG;AACH,qBAAa,KAAK;IAChB,OAAO,CAAC,MAAM,CAAqB;IAEnC,OAAO,CAAC,IAAI,CAAuB;IAEnC,IAAI,GAAG,kBAEN;IAED;;;;;OAKG;IACG,OAAO,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC;IAoBhD;;;;;OAKG;IACG,mBAAmB,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;CAShE;AAED,qBAAa,UAAU;IACT,OAAO,CAAC,QAAQ,CAAC,QAAQ;gBAAR,QAAQ,EAAE,MAAM,IAAI;IAEjD;;OAEG;IACH,OAAO,IAAI,IAAI;IAIf,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,IAAI;CAGzB;AAaD;;;;GAIG;AACH,eAAO,MAAM,YAAY,WACf,GAAG,gBACG,MAAM,gDAC0B,GAAG,KAAK,GAAG,UAuB1D,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=mutex.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mutex.test.d.ts","sourceRoot":"","sources":["../../../src/mutex.test.ts"],"names":[],"mappings":""}
@@ -1 +1 @@
1
- {"version":3,"file":"observable.d.ts","sourceRoot":"","sources":["../../../src/observable.ts"],"names":[],"mappings":"AAIA,OAAO,UAAU,MAAM,gBAAgB,CAAC;AACxC,OAAO,KAAK,EAAE,cAAc,EAAY,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAC/E,OAAO,UAAU,MAAM,UAAU,CAAC;AAElC,OAAO,EAAE,KAAK,KAAK,EAAE,MAAM,UAAU,CAAC;AAGtC,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,KAAK,UAAU,EAAE,CAAC;AAEnD;;;;GAIG;AAIH,qBAAa,mBAAmB,CAAC,CAAC,CAAE,SAAQ,UAAU,CAAC,CAAC,CAAC;IAKA,SAAS,CAAC,MAAM,CAAC;IAJxE,OAAO,CAAC,QAAQ,CAAC,UAAU,CAA0B;IACrD,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAgB;IAC5C,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAiB;gBAEhC,UAAU,EAAE,UAAU,CAAC,CAAC,CAAC,GAAG,UAAU,CAAC,CAAC,CAAC,EAAY,MAAM,CAAC,eAAG;WAU3D,IAAI,CAAC,CAAC,EAAE,KAAK,EAAE,UAAU,CAAC,CAAC,CAAC,GAAG,cAAc,CAAC,CAAC,CAAC,GAAG,SAAS,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,EAAE,YAAY,CAAC,EAAE,CAAC;WAc5F,EAAE,CAAC,CAAC,EAAE,GAAG,KAAK,EAAE,CAAC,EAAE;IAInC;;OAEG;IACH,MAAM,CAAC,KAAK;IAIZ;;OAEG;IACH,GAAG,IAAI,CAAC;IAWR;;;;OAIG;IACG,IAAI,CAAC,EAAE,OAAO,EAAE,GAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAA;KAAO,GAAG,OAAO,CAAC,CAAC,CAAC;IAKrD,OAAO,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IAIpD,GAAG,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,GAAG,mBAAmB,CAAC,CAAC,CAAC;IAIzD,MAAM,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,OAAO,GAAG,mBAAmB,CAAC,CAAC,CAAC;IAO/D,MAAM,CAAC,CAAC,GAAG,CAAC,EAAE,QAAQ,EAAE,CAAC,aAAa,EAAE,CAAC,EAAE,YAAY,EAAE,CAAC,KAAK,CAAC,EAAE,YAAY,CAAC,EAAE,CAAC,GAAG,mBAAmB,CAAC,CAAC,CAAC;IAO3G,OAAO,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,mBAAmB,CAAC,CAAC,CAAC,GAAG,mBAAmB,CAAC,CAAC,CAAC;IAIlF,MAAM,CAAC,CAAC,EAAE,GAAG,WAAW,EAAE,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,GAAG,mBAAmB,CAAC,CAAC,CAAC;IAIhF;;;;;OAKG;IACH,cAAc,CAAC,CAAC,EACd,OAAO,EAAE,CAAC,YAAY,EAAE,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,KAAK,CAAC,EAC/C,GAAG,WAAW,EAAE,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,GACnC,mBAAmB,CAAC,CAAC,CAAC;IAWzB,OAAO,CAAC,UAAU;IAclB,OAAO,CAAC,SAAS,CAYf;CACH"}
1
+ {"version":3,"file":"observable.d.ts","sourceRoot":"","sources":["../../../src/observable.ts"],"names":[],"mappings":"AAIA,OAAO,UAAU,MAAM,gBAAgB,CAAC;AACxC,OAAO,KAAK,EAAE,cAAc,EAAY,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAC/E,OAAO,UAAU,MAAM,UAAU,CAAC;AAElC,OAAO,EAAE,KAAK,KAAK,EAAE,MAAM,UAAU,CAAC;AAGtC,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,KAAK,UAAU,EAAE,CAAC;AAEnD;;;;GAIG;AAIH,qBAAa,mBAAmB,CAAC,CAAC,CAAE,SAAQ,UAAU,CAAC,CAAC,CAAC;IAOrD,SAAS,CAAC,MAAM,CAAC;IANnB,OAAO,CAAC,QAAQ,CAAC,UAAU,CAA0B;IACrD,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAgB;IAC5C,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAiB;gBAG1C,UAAU,EAAE,UAAU,CAAC,CAAC,CAAC,GAAG,UAAU,CAAC,CAAC,CAAC,EAC/B,MAAM,CAAC,eAAG;WAWN,IAAI,CAAC,CAAC,EAAE,KAAK,EAAE,UAAU,CAAC,CAAC,CAAC,GAAG,cAAc,CAAC,CAAC,CAAC,GAAG,SAAS,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,EAAE,YAAY,CAAC,EAAE,CAAC;WAc5F,EAAE,CAAC,CAAC,EAAE,GAAG,KAAK,EAAE,CAAC,EAAE;IAInC;;OAEG;IACH,MAAM,CAAC,KAAK;IAIZ;;OAEG;IACH,GAAG,IAAI,CAAC;IAWR;;;;OAIG;IACG,IAAI,CAAC,EAAE,OAAO,EAAE,GAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAA;KAAO,GAAG,OAAO,CAAC,CAAC,CAAC;IAKrD,OAAO,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IAIpD,GAAG,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,GAAG,mBAAmB,CAAC,CAAC,CAAC;IAIzD,MAAM,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,OAAO,GAAG,mBAAmB,CAAC,CAAC,CAAC;IAO/D,MAAM,CAAC,CAAC,GAAG,CAAC,EAAE,QAAQ,EAAE,CAAC,aAAa,EAAE,CAAC,EAAE,YAAY,EAAE,CAAC,KAAK,CAAC,EAAE,YAAY,CAAC,EAAE,CAAC,GAAG,mBAAmB,CAAC,CAAC,CAAC;IAO3G,OAAO,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,mBAAmB,CAAC,CAAC,CAAC,GAAG,mBAAmB,CAAC,CAAC,CAAC;IAIlF,MAAM,CAAC,CAAC,EAAE,GAAG,WAAW,EAAE,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,GAAG,mBAAmB,CAAC,CAAC,CAAC;IAIhF;;;;;OAKG;IACH,cAAc,CAAC,CAAC,EACd,OAAO,EAAE,CAAC,YAAY,EAAE,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,KAAK,CAAC,EAC/C,GAAG,WAAW,EAAE,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,GACnC,mBAAmB,CAAC,CAAC,CAAC;IAWzB,OAAO,CAAC,UAAU;IAclB,OAAO,CAAC,SAAS,CAYf;CACH"}
@@ -1 +1 @@
1
- {"version":3,"file":"task-scheduling.d.ts","sourceRoot":"","sources":["../../../src/task-scheduling.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,OAAO,EAAE,MAAM,eAAe,CAAC;AAE7C,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,YAAY,CAAC;AAI/C,MAAM,MAAM,aAAa,GAAG,MAAM,IAAI,CAAC;AAEvC;;;;GAIG;AACH,qBAAa,YAAY;IAIX,OAAO,CAAC,QAAQ,CAAC,IAAI;IAAW,OAAO,CAAC,QAAQ,CAAC,SAAS;IAHtE,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,QAAQ,CAA8B;gBAEjB,IAAI,EAAE,OAAO,EAAmB,SAAS,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC;IAE3F,QAAQ;CAkBT;AAED,eAAO,MAAM,YAAY,QAAS,OAAO,MAAM,MAAM,IAAI,SAMxD,CAAC;AAEF,eAAO,MAAM,iBAAiB,QAAe,OAAO,MAAM,MAAM,aAAa,IAAI,CAAC,kBAMjF,CAAC;AAEF,eAAO,MAAM,iBAAiB,QAAS,OAAO,MAAM,MAAM,aAAa,IAAI,CAAC,SAO3E,CAAC;AAEF,eAAO,MAAM,YAAY,QAAS,OAAO,MAAM,MAAM,aAAa,IAAI,CAAC,YAAY,MAAM,SAgBxF,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,oBAAoB,QAAS,OAAO,QAAQ,MAAM,QAAQ,IAAI,CAAC,YAAY,MAAM,SAqB7F,CAAC;AAEF,eAAO,MAAM,sCAAsC,QAC5C,OAAO,QACN,MAAM,QAAQ,IAAI,CAAC,mBACR,MAAM,SAwBxB,CAAC"}
1
+ {"version":3,"file":"task-scheduling.d.ts","sourceRoot":"","sources":["../../../src/task-scheduling.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,OAAO,EAAE,MAAM,eAAe,CAAC;AAE7C,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,YAAY,CAAC;AAI/C,MAAM,MAAM,aAAa,GAAG,MAAM,IAAI,CAAC;AAEvC;;;;GAIG;AACH,qBAAa,YAAY;IAKrB,OAAO,CAAC,QAAQ,CAAC,IAAI;IACrB,OAAO,CAAC,QAAQ,CAAC,SAAS;IAL5B,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,QAAQ,CAA8B;gBAG3B,IAAI,EAAE,OAAO,EACb,SAAS,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC;IAGjD,QAAQ;CAkBT;AAED,eAAO,MAAM,YAAY,QAAS,OAAO,MAAM,MAAM,IAAI,SAMxD,CAAC;AAEF,eAAO,MAAM,iBAAiB,QAAe,OAAO,MAAM,MAAM,aAAa,IAAI,CAAC,kBAMjF,CAAC;AAEF,eAAO,MAAM,iBAAiB,QAAS,OAAO,MAAM,MAAM,aAAa,IAAI,CAAC,SAO3E,CAAC;AAEF,eAAO,MAAM,YAAY,QAAS,OAAO,MAAM,MAAM,aAAa,IAAI,CAAC,YAAY,MAAM,SAgBxF,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,oBAAoB,QAAS,OAAO,QAAQ,MAAM,QAAQ,IAAI,CAAC,YAAY,MAAM,SAqB7F,CAAC;AAEF,eAAO,MAAM,sCAAsC,QAC5C,OAAO,QACN,MAAM,QAAQ,IAAI,CAAC,mBACR,MAAM,SAwBxB,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dxos/async",
3
- "version": "0.3.11-next.0fb359e",
3
+ "version": "0.3.11-next.e28df4f",
4
4
  "description": "Async utilities.",
5
5
  "homepage": "https://dxos.org",
6
6
  "bugs": "https://github.com/dxos/dxos/issues",
@@ -18,11 +18,11 @@
18
18
  "dependencies": {
19
19
  "zen-observable": "^0.10.0",
20
20
  "zen-push": "^0.3.1",
21
- "@dxos/context": "0.3.11-next.0fb359e",
22
- "@dxos/invariant": "0.3.11-next.0fb359e",
23
- "@dxos/node-std": "0.3.11-next.0fb359e",
24
- "@dxos/util": "0.3.11-next.0fb359e",
25
- "@dxos/debug": "0.3.11-next.0fb359e"
21
+ "@dxos/context": "0.3.11-next.e28df4f",
22
+ "@dxos/debug": "0.3.11-next.e28df4f",
23
+ "@dxos/invariant": "0.3.11-next.e28df4f",
24
+ "@dxos/node-std": "0.3.11-next.e28df4f",
25
+ "@dxos/util": "0.3.11-next.e28df4f"
26
26
  },
27
27
  "devDependencies": {
28
28
  "@types/zen-observable": "^0.8.3"
package/src/index.ts CHANGED
@@ -11,7 +11,7 @@ export * from './events';
11
11
  export * from './latch';
12
12
  export * from './observable';
13
13
  export * from './observable-value';
14
- export * from './lock';
14
+ export * from './mutex';
15
15
  export * from './sink';
16
16
  export * from './stream-to-array';
17
17
  export * from './timeout';
@@ -7,47 +7,47 @@ import { expect } from 'chai';
7
7
  import { expectToThrow } from '@dxos/debug';
8
8
  import { describe, test } from '@dxos/test';
9
9
 
10
- import { Lock, synchronized } from './lock';
10
+ import { Mutex, synchronized } from './mutex';
11
11
  import { sleep } from './timeout';
12
12
 
13
- describe('Lock', () => {
13
+ describe('Mutex', () => {
14
14
  test('single execution', async () => {
15
15
  const events = [];
16
- const lock = new Lock();
16
+ const mutex = new Mutex();
17
17
 
18
- await lock.executeSynchronized(async () => {
19
- events.push('lock');
18
+ await mutex.executeSynchronized(async () => {
19
+ events.push('mutex');
20
20
  });
21
21
  events.push('after');
22
22
 
23
- expect(events).to.deep.equal(['lock', 'after']);
23
+ expect(events).to.deep.equal(['mutex', 'after']);
24
24
  });
25
25
 
26
26
  test('return value', async () => {
27
- const lock = new Lock();
27
+ const mutex = new Mutex();
28
28
 
29
- const value = await lock.executeSynchronized(async () => 'foo');
29
+ const value = await mutex.executeSynchronized(async () => 'foo');
30
30
 
31
31
  expect(value).to.equal('foo');
32
32
  });
33
33
 
34
34
  test('two concurrent synchronizations', async () => {
35
35
  const events = [];
36
- const lock = new Lock();
36
+ const mutex = new Mutex();
37
37
 
38
- const p1 = lock
38
+ const p1 = mutex
39
39
  .executeSynchronized(async () => {
40
- events.push('lock1');
40
+ events.push('mutex1');
41
41
  await sleep(10);
42
- events.push('lock2');
42
+ events.push('mutex2');
43
43
  })
44
44
  .then(() => {
45
45
  events.push('p1 resolve');
46
46
  });
47
47
 
48
- const p2 = lock
48
+ const p2 = mutex
49
49
  .executeSynchronized(async () => {
50
- events.push('lock3');
50
+ events.push('mutex3');
51
51
  })
52
52
  .then(() => {
53
53
  events.push('p2 resolve');
@@ -57,14 +57,14 @@ describe('Lock', () => {
57
57
  await p2;
58
58
  events.push('after');
59
59
 
60
- expect(events).to.deep.equal(['lock1', 'lock2', 'p1 resolve', 'lock3', 'p2 resolve', 'after']);
60
+ expect(events).to.deep.equal(['mutex1', 'mutex2', 'p1 resolve', 'mutex3', 'p2 resolve', 'after']);
61
61
  });
62
62
 
63
- test('deadlock', async () => {
64
- const lock = new Lock();
63
+ test('deadmutex', async () => {
64
+ const mutex = new Mutex();
65
65
 
66
- const promise = lock.executeSynchronized(async () => {
67
- await lock.executeSynchronized(async () => {
66
+ const promise = mutex.executeSynchronized(async () => {
67
+ await mutex.executeSynchronized(async () => {
68
68
  /* No-op. */
69
69
  });
70
70
  });
@@ -79,12 +79,12 @@ describe('Lock', () => {
79
79
  expect(resolved).to.be.false;
80
80
  });
81
81
 
82
- test('errors do not break the lock', async () => {
83
- const lock = new Lock();
82
+ test('errors do not break the mutex', async () => {
83
+ const mutex = new Mutex();
84
84
 
85
85
  let p1Status, p2Status;
86
86
 
87
- const p1 = lock
87
+ const p1 = mutex
88
88
  .executeSynchronized(async () => {
89
89
  throw new Error();
90
90
  })
@@ -97,7 +97,7 @@ describe('Lock', () => {
97
97
  },
98
98
  );
99
99
 
100
- const p2 = lock
100
+ const p2 = mutex
101
101
  .executeSynchronized(async () => {
102
102
  /* No-op. */
103
103
  })
@@ -118,16 +118,16 @@ describe('Lock', () => {
118
118
  });
119
119
 
120
120
  test('errors are propagated with stack traces', async () => {
121
- const lock = new Lock();
121
+ const mutex = new Mutex();
122
122
 
123
123
  const throwsError = async () => {
124
124
  throw new Error();
125
125
  };
126
126
 
127
127
  let error: Error;
128
- const callLock = async () => {
128
+ const callmutex = async () => {
129
129
  try {
130
- await lock.executeSynchronized(async () => {
130
+ await mutex.executeSynchronized(async () => {
131
131
  await throwsError();
132
132
  });
133
133
  } catch (err: any) {
@@ -136,11 +136,34 @@ describe('Lock', () => {
136
136
  }
137
137
  };
138
138
 
139
- await expectToThrow(() => callLock());
139
+ await expectToThrow(() => callmutex());
140
140
 
141
141
  expect(error!.stack!.includes('throwsError')).to.be.true;
142
- expect(error!.stack!.includes('callLock')).to.be.true;
142
+ expect(error!.stack!.includes('callmutex')).to.be.true;
143
143
  }).skipEnvironments('webkit');
144
+
145
+ test('works with explicit resource management syntax', async () => {
146
+ const mutex = new Mutex();
147
+
148
+ const events: string[] = [];
149
+
150
+ const p1 = (async () => {
151
+ using _guard = await mutex.acquire();
152
+ events.push('acquire one');
153
+ await sleep(10);
154
+ events.push('end one');
155
+ })();
156
+
157
+ const p2 = (async () => {
158
+ using _guard = await mutex.acquire();
159
+ events.push('acquire two');
160
+ await sleep(10);
161
+ events.push('end two');
162
+ })();
163
+
164
+ await Promise.all([p1, p2]);
165
+ expect(events).to.deep.equal(['acquire one', 'end one', 'acquire two', 'end two']);
166
+ });
144
167
  });
145
168
 
146
169
  class TestClass {
@@ -20,7 +20,7 @@ import { warnAfterTimeout } from '@dxos/debug';
20
20
  * Java docs reference on synchronized sections:
21
21
  * https://docs.oracle.com/javase/tutorial/essential/concurrency/locksync.html
22
22
  */
23
- export class Lock {
23
+ export class Mutex {
24
24
  private _queue = Promise.resolve();
25
25
 
26
26
  private _tag: string | null = null;
@@ -35,16 +35,16 @@ export class Lock {
35
35
  * NOTE: Using `executeSynchronized` is preferred over using `acquire` directly.
36
36
  * @returns Release callback
37
37
  */
38
- async acquire(tag?: string): Promise<() => void> {
38
+ async acquire(tag?: string): Promise<MutexGuard> {
39
39
  const prev = this._queue;
40
40
 
41
41
  // Immediately update the promise before invoking any async actions so that next invocation waits for our task to complete.
42
- let release!: () => void;
42
+ let guard!: MutexGuard;
43
43
  this._queue = new Promise((resolve) => {
44
- release = () => {
44
+ guard = new MutexGuard(() => {
45
45
  this._tag = null;
46
46
  resolve();
47
- };
47
+ });
48
48
  });
49
49
 
50
50
  await prev;
@@ -52,7 +52,7 @@ export class Lock {
52
52
  if (tag !== undefined) {
53
53
  this._tag = tag;
54
54
  }
55
- return release;
55
+ return guard;
56
56
  }
57
57
 
58
58
  /**
@@ -62,20 +62,35 @@ export class Lock {
62
62
  * WARNING: Calling `executeSynchronized` inside of `executeSynchronized` on the same lock instance is a deadlock.
63
63
  */
64
64
  async executeSynchronized<T>(fun: () => Promise<T>): Promise<T> {
65
- const release = await this.acquire();
65
+ const guard = await this.acquire();
66
66
 
67
67
  try {
68
68
  return await fun();
69
69
  } finally {
70
- release();
70
+ guard.release();
71
71
  }
72
72
  }
73
73
  }
74
74
 
75
- const classLockSymbol = Symbol('class-lock');
75
+ export class MutexGuard {
76
+ constructor(private readonly _release: () => void) {}
77
+
78
+ /**
79
+ * Releases the lock.
80
+ */
81
+ release(): void {
82
+ this._release();
83
+ }
84
+
85
+ [Symbol.dispose](): void {
86
+ this.release();
87
+ }
88
+ }
89
+
90
+ const classMutexSymbol = Symbol('class-mutex');
76
91
 
77
92
  interface LockableClass {
78
- [classLockSymbol]?: Lock;
93
+ [classMutexSymbol]?: Mutex;
79
94
  }
80
95
 
81
96
  const FORCE_DISABLE_WARNING = false;
@@ -95,22 +110,22 @@ export const synchronized = (
95
110
  ) => {
96
111
  const method = descriptor.value!;
97
112
  descriptor.value = async function synchronizedMethod(this: any & LockableClass, ...args: any) {
98
- const lock: Lock = (this[classLockSymbol] ??= new Lock());
113
+ const mutex: Mutex = (this[classMutexSymbol] ??= new Mutex());
99
114
 
100
115
  const tag = `${target.constructor.name}.${propertyName}`;
101
116
 
102
117
  // Disable warning in prod to avoid performance penalty.
103
- let release;
118
+ let guard;
104
119
  if (!enableWarning) {
105
- release = await lock.acquire(tag);
120
+ guard = await mutex.acquire(tag);
106
121
  } else {
107
- release = await warnAfterTimeout(10_000, `lock on ${tag} (taken by ${lock.tag})`, () => lock.acquire(tag));
122
+ guard = await warnAfterTimeout(10_000, `lock on ${tag} (taken by ${mutex.tag})`, () => mutex.acquire(tag));
108
123
  }
109
124
 
110
125
  try {
111
126
  return await method.apply(this, args);
112
127
  } finally {
113
- release();
128
+ guard.release();
114
129
  }
115
130
  };
116
131
  Object.defineProperty(descriptor.value, 'name', { value: propertyName + '$synchronized' });
package/src/observable.ts CHANGED
@@ -24,7 +24,10 @@ export class MulticastObservable<T> extends Observable<T> {
24
24
  private readonly _observable: Observable<T>;
25
25
  private readonly _completed = new Trigger();
26
26
 
27
- constructor(subscriber: Observable<T> | Subscriber<T>, protected _value?: T) {
27
+ constructor(
28
+ subscriber: Observable<T> | Subscriber<T>,
29
+ protected _value?: T,
30
+ ) {
28
31
  super((observer) => this._subscribe(observer));
29
32
 
30
33
  this._observable = typeof subscriber === 'function' ? new Observable(subscriber) : subscriber;
@@ -19,7 +19,10 @@ export class DeferredTask {
19
19
  private _scheduled = false;
20
20
  private _promise: Promise<void> | null = null; // Can't be rejected.
21
21
 
22
- constructor(private readonly _ctx: Context, private readonly _callback: () => Promise<void>) {}
22
+ constructor(
23
+ private readonly _ctx: Context,
24
+ private readonly _callback: () => Promise<void>,
25
+ ) {}
23
26
 
24
27
  schedule() {
25
28
  if (this._scheduled) {
@@ -1 +0,0 @@
1
- {"version":3,"file":"lock.d.ts","sourceRoot":"","sources":["../../../src/lock.ts"],"names":[],"mappings":"AAMA;;;;;;;;;;;;;;;GAeG;AACH,qBAAa,IAAI;IACf,OAAO,CAAC,MAAM,CAAqB;IAEnC,OAAO,CAAC,IAAI,CAAuB;IAEnC,IAAI,GAAG,kBAEN;IAED;;;;;OAKG;IACG,OAAO,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,CAAC;IAoBhD;;;;;OAKG;IACG,mBAAmB,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;CAShE;AAaD;;;;GAIG;AACH,eAAO,MAAM,YAAY,WACf,GAAG,gBACG,MAAM,gDAC0B,GAAG,KAAK,GAAG,UAuB1D,CAAC"}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=lock.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"lock.test.d.ts","sourceRoot":"","sources":["../../../src/lock.test.ts"],"names":[],"mappings":""}