xref: /aosp_15_r20/external/perfetto/ui/src/base/registry.ts (revision 6dbdd20afdafa5e3ca9b8809fa73465d530080dc)
1*6dbdd20aSAndroid Build Coastguard Worker// Copyright (C) 2018 The Android Open Source Project
2*6dbdd20aSAndroid Build Coastguard Worker//
3*6dbdd20aSAndroid Build Coastguard Worker// Licensed under the Apache License, Version 2.0 (the "License");
4*6dbdd20aSAndroid Build Coastguard Worker// you may not use this file except in compliance with the License.
5*6dbdd20aSAndroid Build Coastguard Worker// You may obtain a copy of the License at
6*6dbdd20aSAndroid Build Coastguard Worker//
7*6dbdd20aSAndroid Build Coastguard Worker//      http://www.apache.org/licenses/LICENSE-2.0
8*6dbdd20aSAndroid Build Coastguard Worker//
9*6dbdd20aSAndroid Build Coastguard Worker// Unless required by applicable law or agreed to in writing, software
10*6dbdd20aSAndroid Build Coastguard Worker// distributed under the License is distributed on an "AS IS" BASIS,
11*6dbdd20aSAndroid Build Coastguard Worker// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*6dbdd20aSAndroid Build Coastguard Worker// See the License for the specific language governing permissions and
13*6dbdd20aSAndroid Build Coastguard Worker// limitations under the License.
14*6dbdd20aSAndroid Build Coastguard Worker
15*6dbdd20aSAndroid Build Coastguard Workerexport interface HasKind {
16*6dbdd20aSAndroid Build Coastguard Worker  kind: string;
17*6dbdd20aSAndroid Build Coastguard Worker}
18*6dbdd20aSAndroid Build Coastguard Worker
19*6dbdd20aSAndroid Build Coastguard Workerexport class RegistryError extends Error {
20*6dbdd20aSAndroid Build Coastguard Worker  constructor(message?: string) {
21*6dbdd20aSAndroid Build Coastguard Worker    super(message);
22*6dbdd20aSAndroid Build Coastguard Worker    this.name = this.constructor.name;
23*6dbdd20aSAndroid Build Coastguard Worker  }
24*6dbdd20aSAndroid Build Coastguard Worker}
25*6dbdd20aSAndroid Build Coastguard Worker
26*6dbdd20aSAndroid Build Coastguard Workerexport class Registry<T> {
27*6dbdd20aSAndroid Build Coastguard Worker  private key: (t: T) => string;
28*6dbdd20aSAndroid Build Coastguard Worker  protected registry: Map<string, T>;
29*6dbdd20aSAndroid Build Coastguard Worker
30*6dbdd20aSAndroid Build Coastguard Worker  static kindRegistry<T extends HasKind>(): Registry<T> {
31*6dbdd20aSAndroid Build Coastguard Worker    return new Registry<T>((t) => t.kind);
32*6dbdd20aSAndroid Build Coastguard Worker  }
33*6dbdd20aSAndroid Build Coastguard Worker
34*6dbdd20aSAndroid Build Coastguard Worker  constructor(key: (t: T) => string) {
35*6dbdd20aSAndroid Build Coastguard Worker    this.registry = new Map<string, T>();
36*6dbdd20aSAndroid Build Coastguard Worker    this.key = key;
37*6dbdd20aSAndroid Build Coastguard Worker  }
38*6dbdd20aSAndroid Build Coastguard Worker
39*6dbdd20aSAndroid Build Coastguard Worker  register(registrant: T): Disposable {
40*6dbdd20aSAndroid Build Coastguard Worker    const kind = this.key(registrant);
41*6dbdd20aSAndroid Build Coastguard Worker    if (this.registry.has(kind)) {
42*6dbdd20aSAndroid Build Coastguard Worker      throw new RegistryError(
43*6dbdd20aSAndroid Build Coastguard Worker        `Registrant ${kind} already exists in the registry`,
44*6dbdd20aSAndroid Build Coastguard Worker      );
45*6dbdd20aSAndroid Build Coastguard Worker    }
46*6dbdd20aSAndroid Build Coastguard Worker    this.registry.set(kind, registrant);
47*6dbdd20aSAndroid Build Coastguard Worker
48*6dbdd20aSAndroid Build Coastguard Worker    return {
49*6dbdd20aSAndroid Build Coastguard Worker      [Symbol.dispose]: () => this.registry.delete(kind),
50*6dbdd20aSAndroid Build Coastguard Worker    };
51*6dbdd20aSAndroid Build Coastguard Worker  }
52*6dbdd20aSAndroid Build Coastguard Worker
53*6dbdd20aSAndroid Build Coastguard Worker  has(kind: string): boolean {
54*6dbdd20aSAndroid Build Coastguard Worker    return this.registry.has(kind);
55*6dbdd20aSAndroid Build Coastguard Worker  }
56*6dbdd20aSAndroid Build Coastguard Worker
57*6dbdd20aSAndroid Build Coastguard Worker  get(kind: string): T {
58*6dbdd20aSAndroid Build Coastguard Worker    const registrant = this.registry.get(kind);
59*6dbdd20aSAndroid Build Coastguard Worker    if (registrant === undefined) {
60*6dbdd20aSAndroid Build Coastguard Worker      throw new RegistryError(`${kind} has not been registered.`);
61*6dbdd20aSAndroid Build Coastguard Worker    }
62*6dbdd20aSAndroid Build Coastguard Worker    return registrant;
63*6dbdd20aSAndroid Build Coastguard Worker  }
64*6dbdd20aSAndroid Build Coastguard Worker
65*6dbdd20aSAndroid Build Coastguard Worker  tryGet(kind: string): T | undefined {
66*6dbdd20aSAndroid Build Coastguard Worker    return this.registry.get(kind);
67*6dbdd20aSAndroid Build Coastguard Worker  }
68*6dbdd20aSAndroid Build Coastguard Worker
69*6dbdd20aSAndroid Build Coastguard Worker  // Support iteration: for (const foo of fooRegistry.values()) { ... }
70*6dbdd20aSAndroid Build Coastguard Worker  *values() {
71*6dbdd20aSAndroid Build Coastguard Worker    yield* this.registry.values();
72*6dbdd20aSAndroid Build Coastguard Worker  }
73*6dbdd20aSAndroid Build Coastguard Worker
74*6dbdd20aSAndroid Build Coastguard Worker  valuesAsArray(): ReadonlyArray<T> {
75*6dbdd20aSAndroid Build Coastguard Worker    return Array.from(this.values());
76*6dbdd20aSAndroid Build Coastguard Worker  }
77*6dbdd20aSAndroid Build Coastguard Worker
78*6dbdd20aSAndroid Build Coastguard Worker  unregisterAllForTesting(): void {
79*6dbdd20aSAndroid Build Coastguard Worker    this.registry.clear();
80*6dbdd20aSAndroid Build Coastguard Worker  }
81*6dbdd20aSAndroid Build Coastguard Worker}
82