Last active
June 22, 2023 22:29
-
-
Save rbuckton/49e2d4a5e2b691d393f146f8c1b8f19a to your computer and use it in GitHub Desktop.
SafeHandle
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
// a simple SafeHandle with a public `dangerousGetHandle` method. | |
class SafeHandle { | |
static #finalizer = new FinalizationRegistry(({ handle, releaseHandle }) => { | |
releaseHandle(handle); | |
}); | |
#data = null; | |
constructor(handle, releaseHandle) { | |
this.#data = { handle, releaseHandle }; | |
SafeHandle.#finalizer.register(this, this.#data, this); | |
} | |
get disposed() { | |
return this.#data === null; | |
} | |
// public, so anyone could get the handle | |
dangerousGetHandle() { | |
if (this.#data === null) throw new ReferenceError("Object is disposed"); | |
return this.#data.handle; | |
} | |
dispose() { | |
if (this.#data !== null) { | |
SafeHandle.#finalizer.unregister(this); | |
const { handle, releaseHandle } = this.#data; | |
this.#data = null; | |
releaseHandle(handle); | |
} | |
} | |
[Symbol.dispose]() { | |
return this.dispose(); | |
} | |
} | |
// usage: | |
function cleanupHandle(unsafeHandle) { ... } | |
class MyHandle extends SafeHandle { | |
constructor(handle) { | |
super(handle, cleanupHandle); | |
} | |
read() { | |
// dangerousGetHandle guards against disposal for you | |
return nativeMethods.read(this.dangerousGetHandle()); | |
} | |
} |
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
// a simple SafeHandle without a public method to access the handle. | |
class SafeHandle { | |
static #finalizer = new FinalizationRegistry(({ handle, releaseHandle }) => { | |
releaseHandle(handle); | |
}); | |
#data = null; | |
constructor(handle, releaseHandle) { | |
this.#data = { handle, releaseHandle }; | |
SafeHandle.#finalizer.register(this, this.#data, this); | |
} | |
get disposed() { | |
return this.#data === null; | |
} | |
dispose() { | |
if (this.#data !== null) { | |
SafeHandle.#finalizer.unregister(this); | |
const { handle, releaseHandle } = this.#data; | |
this.#data = null; | |
releaseHandle(handle); | |
} | |
} | |
[Symbol.dispose]() { | |
return this.dispose(); | |
} | |
} | |
// usage: | |
function cleanupHandle(unsafeHandle) { ... } | |
class MyHandle extends SafeHandle { | |
#handle; | |
constructor(handle) { | |
super(handle, cleanupHandle); | |
this.#handle = handle; | |
} | |
// no public superclass method, so we use our own private method | |
// to guard against disposal | |
#dangerousGetHandle() { | |
if (super.disposed) throw new ReferenceError("Object disposed."); | |
return this.#handle; | |
} | |
read() { | |
return nativeMethods.read(this.#dangerousGetHandle()); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment