Line data Source code
1 : import { LoggableException } from "../platform/logger/logger.js";
2 :
3 1 : const LOG_CTX = 'async_value';
4 :
5 : type Resolver<Value> = (value: Value) => void;
6 : type Rejecter<Error> = (value: Error) => void;
7 :
8 1 : enum AsyncValueStatus {
9 1 : PENDING = 0,
10 1 : RESOLVED = 1,
11 1 : REJECTED = 2
12 1 : }
13 :
14 1 : export class AsyncValue<Value, Error> {
15 1 : protected status: AsyncValueStatus;
16 1 : protected resolvedValue: Value | null;
17 1 : protected rejectionError: Error | null;
18 :
19 1 : protected valuePromise: Promise<Value> | null;
20 1 : protected resolveFn: Resolver<Value> | null;
21 1 : protected rejectFn: Rejecter<Error> | null;
22 :
23 1 : constructor() {
24 1 : this.status = AsyncValueStatus.PENDING;
25 1 : this.resolvedValue = null;
26 1 : this.rejectionError = null;
27 1 : this.valuePromise = null;
28 1 : this.resolveFn = null;
29 1 : this.rejectFn = null;
30 1 : }
31 :
32 1 : public isResolved(): boolean {
33 1 : return this.status != AsyncValueStatus.PENDING;
34 1 : }
35 1 : public async getValue(): Promise<Value> {
36 1 : switch (this.status) {
37 1 : case AsyncValueStatus.RESOLVED:
38 1 : return Promise.resolve(this.resolvedValue!);
39 1 : case AsyncValueStatus.REJECTED:
40 1 : return Promise.reject(this.rejectionError!);
41 1 : case AsyncValueStatus.PENDING: {
42 1 : if (this.valuePromise == null) {
43 1 : this.valuePromise = new Promise<Value>((resolve, reject) => {
44 1 : this.resolveFn = resolve;
45 1 : this.rejectFn = reject
46 1 : });
47 : }
48 1 : return this.valuePromise;
49 : }
50 1 : }
51 1 : }
52 1 : public getResolvedValue(): Value {
53 1 : switch (this.status) {
54 1 : case AsyncValueStatus.RESOLVED:
55 1 : return this.resolvedValue!;
56 0 : case AsyncValueStatus.REJECTED:
57 0 : throw this.rejectionError;
58 0 : case AsyncValueStatus.PENDING:
59 0 : throw new Error("async value is not resolved");
60 1 : }
61 1 : }
62 1 : public resolve(value: Value) {
63 1 : if (this.status != AsyncValueStatus.PENDING) {
64 0 : throw new LoggableException("tried to resolve an async value that is not pending", {}, LOG_CTX);
65 : }
66 1 : this.resolvedValue = value;
67 1 : this.status = AsyncValueStatus.RESOLVED;
68 1 : if (this.resolveFn != null) {
69 1 : this.resolveFn(value);
70 : }
71 1 : }
72 1 : public reject(error: Error) {
73 1 : if (this.status != AsyncValueStatus.PENDING) {
74 0 : throw new LoggableException(`tried to reject an async value that is not pending with error: ${error}`, {}, LOG_CTX);
75 : }
76 1 : this.rejectionError = error;
77 1 : this.status = AsyncValueStatus.REJECTED;
78 1 : if (this.rejectFn != null) {
79 1 : this.rejectFn(error);
80 : }
81 1 : }
82 1 : }
|