Last active
May 29, 2022 06:48
-
-
Save rasmusmerzin/0668e60e3bf9b0118e2f212beea4d15a to your computer and use it in GitHub Desktop.
Typescript LockMap<T>
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { LockMap, LockMapEvent } from "./lock-map"; | |
const { Release, Change, Acquire } = LockMapEvent; | |
describe("LockMap<void>", () => { | |
let events: LockMapEvent[]; | |
let lockSet: LockMap<void>; | |
beforeEach(() => { | |
events = []; | |
lockSet = new LockMap(); | |
for (const type of <LockMapEvent[]>Object.values(LockMapEvent)) | |
lockSet.addEventListener(type, () => events.push(type)); | |
}); | |
it("set", () => { | |
let ctrl: AbortController; | |
const ctrls = Array.from(Array(2), () => new AbortController()); | |
ctrls.forEach((ctrl) => lockSet.set(ctrl)); | |
expect(events).toStrictEqual([Acquire, Change]); | |
events = []; | |
ctrls.pop()!.abort(); | |
expect(events).toStrictEqual([Change]); | |
events = []; | |
lockSet.set((ctrl = new AbortController())); | |
ctrls.push(ctrl); | |
expect(events).toStrictEqual([Change]); | |
events = []; | |
ctrls.splice(0, Infinity).forEach((ctrl) => ctrl.abort()); | |
expect(events).toStrictEqual([Change, Release]); | |
events = []; | |
lockSet.set((ctrl = new AbortController())); | |
expect(events).toStrictEqual([Acquire]); | |
events = []; | |
ctrl.abort(); | |
expect(events).toStrictEqual([Release]); | |
}); | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
export enum LockMapEvent { | |
Acquire = "acquire", | |
Change = "change", | |
Release = "release", | |
} | |
export class LockMap<T> extends EventTarget { | |
readonly map = new Map<AbortController, T>(); | |
private delete(ctrl: AbortController) { | |
if (!this.map.size) return; | |
this.map.delete(ctrl); | |
if (this.map.size) this.dispatchEvent(new Event(LockMapEvent.Change)); | |
else this.dispatchEvent(new Event(LockMapEvent.Release)); | |
} | |
private has = (ctrl: AbortController, value: T) => | |
this.map.has(ctrl) && this.map.get(ctrl) === value; | |
set = (ctrl: AbortController, value: T) => { | |
if (ctrl.signal.aborted || this.has(ctrl, value)) return; | |
const previousSize = this.map.size; | |
this.map.set(ctrl, value); | |
ctrl.signal.addEventListener("abort", () => this.delete(ctrl)); | |
if (previousSize) return this.dispatchEvent(new Event(LockMapEvent.Change)); | |
else return this.dispatchEvent(new Event(LockMapEvent.Acquire)); | |
}; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment