-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathdisposables.ts
122 lines (99 loc) · 3.3 KB
/
disposables.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
import {ReadonlyDeep} from 'type-fest';
import {convertToArray} from '../array/convertToArray.js';
import {PromiseStore} from '../promise/PromiseStore.js';
import {OrPromise} from '../types.js';
export interface DisposableResource {
dispose?: () => OrPromise<void>;
}
export class DisposablesStore {
protected disposablesMap = new Map<unknown, DisposableResource>();
constructor(protected promises: PromiseStore) {
this.add = this.add.bind(this);
}
add(disposable: DisposableResource | DisposableResource[]): void;
add(key: unknown, disposable: DisposableResource): void;
add(...args: unknown[]) {
if (args.length === 1) {
convertToArray(
args[0] as DisposableResource | DisposableResource[]
).forEach(next => this.disposablesMap.set(next, next));
} else {
this.disposablesMap.set(args[0], args[1] as DisposableResource);
}
}
get = (key: unknown): DisposableResource | undefined => {
return this.disposablesMap.get(key);
};
has = (key: unknown): boolean => {
return this.disposablesMap.has(key);
};
getMap = (): ReadonlyDeep<Map<unknown, DisposableResource>> => {
return this.disposablesMap;
};
getList = (): ReadonlyDeep<DisposableResource[]> => {
return Array.from(this.disposablesMap.values());
};
forgetDisposeAll = () => {
this.disposablesMap.forEach(disposable => {
if (disposable.dispose) {
this.promises.callAndForget(disposable.dispose.bind(disposable));
}
});
this.disposablesMap.clear();
};
awaitDisposeAll = async () => {
const promises: Array<unknown> = [];
this.disposablesMap.forEach(disposable => {
if (disposable.dispose) {
promises.push(disposable.dispose());
}
});
await Promise.all(promises);
this.disposablesMap.clear();
};
/**
* if an individual key is an array, i.e. you called `add` with an array as
* the key, e.g. `add([1, 2, 3], disposable)`, then use `removeOne` instead of
* `remove`
*/
remove = (key: unknown | unknown[]) => {
convertToArray(key).forEach(next => this.disposablesMap.delete(next));
};
removeOne = (key: unknown) => {
this.disposablesMap.delete(key);
};
awaitDisposeOne = async (key: unknown) => {
const disposable = this.disposablesMap.get(key);
if (disposable && disposable.dispose) {
await disposable.dispose();
this.disposablesMap.delete(key);
}
};
forgetDisposeOne = (key: unknown) => {
const disposable = this.disposablesMap.get(key);
if (disposable && disposable.dispose) {
this.promises.callAndForget(disposable.dispose.bind(disposable));
this.disposablesMap.delete(key);
}
};
awaitDisposeMany = async (keys: unknown[]) => {
const promises: Array<unknown> = [];
keys.forEach(key => {
const disposable = this.disposablesMap.get(key);
if (disposable && disposable.dispose) {
promises.push(disposable.dispose());
this.disposablesMap.delete(key);
}
});
await Promise.all(promises);
};
forgetDisposeMany = (keys: unknown[]) => {
keys.forEach(key => {
const disposable = this.disposablesMap.get(key);
if (disposable && disposable.dispose) {
this.promises.callAndForget(disposable.dispose.bind(disposable));
this.disposablesMap.delete(key);
}
});
};
}