first commit
This commit is contained in:
227
node_modules/@tootallnate/quickjs-emscripten/dist/lifetime.js
generated
vendored
Normal file
227
node_modules/@tootallnate/quickjs-emscripten/dist/lifetime.js
generated
vendored
Normal file
@@ -0,0 +1,227 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.Scope = exports.WeakLifetime = exports.StaticLifetime = exports.Lifetime = void 0;
|
||||
const asyncify_helpers_1 = require("./asyncify-helpers");
|
||||
const debug_1 = require("./debug");
|
||||
const errors_1 = require("./errors");
|
||||
/**
|
||||
* A lifetime prevents access to a value after the lifetime has been
|
||||
* [[dispose]]ed.
|
||||
*
|
||||
* Typically, quickjs-emscripten uses Lifetimes to protect C memory pointers.
|
||||
*/
|
||||
class Lifetime {
|
||||
/**
|
||||
* When the Lifetime is disposed, it will call `disposer(_value)`. Use the
|
||||
* disposer function to implement whatever cleanup needs to happen at the end
|
||||
* of `value`'s lifetime.
|
||||
*
|
||||
* `_owner` is not used or controlled by the lifetime. It's just metadata for
|
||||
* the creator.
|
||||
*/
|
||||
constructor(_value, copier, disposer, _owner) {
|
||||
this._value = _value;
|
||||
this.copier = copier;
|
||||
this.disposer = disposer;
|
||||
this._owner = _owner;
|
||||
this._alive = true;
|
||||
this._constructorStack = debug_1.QTS_DEBUG ? new Error("Lifetime constructed").stack : undefined;
|
||||
}
|
||||
get alive() {
|
||||
return this._alive;
|
||||
}
|
||||
/**
|
||||
* The value this Lifetime protects. You must never retain the value - it
|
||||
* may become invalid, leading to memory errors.
|
||||
*
|
||||
* @throws If the lifetime has been [[dispose]]d already.
|
||||
*/
|
||||
get value() {
|
||||
this.assertAlive();
|
||||
return this._value;
|
||||
}
|
||||
get owner() {
|
||||
return this._owner;
|
||||
}
|
||||
get dupable() {
|
||||
return !!this.copier;
|
||||
}
|
||||
/**
|
||||
* Create a new handle pointing to the same [[value]].
|
||||
*/
|
||||
dup() {
|
||||
this.assertAlive();
|
||||
if (!this.copier) {
|
||||
throw new Error("Non-dupable lifetime");
|
||||
}
|
||||
return new Lifetime(this.copier(this._value), this.copier, this.disposer, this._owner);
|
||||
}
|
||||
consume(map) {
|
||||
this.assertAlive();
|
||||
const result = map(this);
|
||||
this.dispose();
|
||||
return result;
|
||||
}
|
||||
/**
|
||||
* Dispose of [[value]] and perform cleanup.
|
||||
*/
|
||||
dispose() {
|
||||
this.assertAlive();
|
||||
if (this.disposer) {
|
||||
this.disposer(this._value);
|
||||
}
|
||||
this._alive = false;
|
||||
}
|
||||
assertAlive() {
|
||||
if (!this.alive) {
|
||||
if (this._constructorStack) {
|
||||
throw new errors_1.QuickJSUseAfterFree(`Lifetime not alive\n${this._constructorStack}\nLifetime used`);
|
||||
}
|
||||
throw new errors_1.QuickJSUseAfterFree("Lifetime not alive");
|
||||
}
|
||||
}
|
||||
}
|
||||
exports.Lifetime = Lifetime;
|
||||
/**
|
||||
* A Lifetime that lives forever. Used for constants.
|
||||
*/
|
||||
class StaticLifetime extends Lifetime {
|
||||
constructor(value, owner) {
|
||||
super(value, undefined, undefined, owner);
|
||||
}
|
||||
// Static lifetime doesn't need a copier to be copiable
|
||||
get dupable() {
|
||||
return true;
|
||||
}
|
||||
// Copy returns the same instance.
|
||||
dup() {
|
||||
return this;
|
||||
}
|
||||
// Dispose does nothing.
|
||||
dispose() { }
|
||||
}
|
||||
exports.StaticLifetime = StaticLifetime;
|
||||
/**
|
||||
* A Lifetime that does not own its `value`. A WeakLifetime never calls its
|
||||
* `disposer` function, but can be `dup`ed to produce regular lifetimes that
|
||||
* do.
|
||||
*
|
||||
* Used for function arguments.
|
||||
*/
|
||||
class WeakLifetime extends Lifetime {
|
||||
constructor(value, copier, disposer, owner) {
|
||||
// We don't care if the disposer doesn't support freeing T
|
||||
super(value, copier, disposer, owner);
|
||||
}
|
||||
dispose() {
|
||||
this._alive = false;
|
||||
}
|
||||
}
|
||||
exports.WeakLifetime = WeakLifetime;
|
||||
function scopeFinally(scope, blockError) {
|
||||
// console.log('scopeFinally', scope, blockError)
|
||||
let disposeError;
|
||||
try {
|
||||
scope.dispose();
|
||||
}
|
||||
catch (error) {
|
||||
disposeError = error;
|
||||
}
|
||||
if (blockError && disposeError) {
|
||||
Object.assign(blockError, {
|
||||
message: `${blockError.message}\n Then, failed to dispose scope: ${disposeError.message}`,
|
||||
disposeError,
|
||||
});
|
||||
throw blockError;
|
||||
}
|
||||
if (blockError || disposeError) {
|
||||
throw blockError || disposeError;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Scope helps reduce the burden of manually tracking and disposing of
|
||||
* Lifetimes. See [[withScope]]. and [[withScopeAsync]].
|
||||
*/
|
||||
class Scope {
|
||||
constructor() {
|
||||
this._disposables = new Lifetime(new Set());
|
||||
}
|
||||
/**
|
||||
* Run `block` with a new Scope instance that will be disposed after the block returns.
|
||||
* Inside `block`, call `scope.manage` on each lifetime you create to have the lifetime
|
||||
* automatically disposed after the block returns.
|
||||
*
|
||||
* @warning Do not use with async functions. Instead, use [[withScopeAsync]].
|
||||
*/
|
||||
static withScope(block) {
|
||||
const scope = new Scope();
|
||||
let blockError;
|
||||
try {
|
||||
return block(scope);
|
||||
}
|
||||
catch (error) {
|
||||
blockError = error;
|
||||
throw error;
|
||||
}
|
||||
finally {
|
||||
scopeFinally(scope, blockError);
|
||||
}
|
||||
}
|
||||
static withScopeMaybeAsync(_this, block) {
|
||||
return (0, asyncify_helpers_1.maybeAsync)(undefined, function* (awaited) {
|
||||
const scope = new Scope();
|
||||
let blockError;
|
||||
try {
|
||||
return yield* awaited.of(block.call(_this, awaited, scope));
|
||||
}
|
||||
catch (error) {
|
||||
blockError = error;
|
||||
throw error;
|
||||
}
|
||||
finally {
|
||||
scopeFinally(scope, blockError);
|
||||
}
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Run `block` with a new Scope instance that will be disposed after the
|
||||
* block's returned promise settles. Inside `block`, call `scope.manage` on each
|
||||
* lifetime you create to have the lifetime automatically disposed after the
|
||||
* block returns.
|
||||
*/
|
||||
static async withScopeAsync(block) {
|
||||
const scope = new Scope();
|
||||
let blockError;
|
||||
try {
|
||||
return await block(scope);
|
||||
}
|
||||
catch (error) {
|
||||
blockError = error;
|
||||
throw error;
|
||||
}
|
||||
finally {
|
||||
scopeFinally(scope, blockError);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Track `lifetime` so that it is disposed when this scope is disposed.
|
||||
*/
|
||||
manage(lifetime) {
|
||||
this._disposables.value.add(lifetime);
|
||||
return lifetime;
|
||||
}
|
||||
get alive() {
|
||||
return this._disposables.alive;
|
||||
}
|
||||
dispose() {
|
||||
const lifetimes = Array.from(this._disposables.value.values()).reverse();
|
||||
for (const lifetime of lifetimes) {
|
||||
if (lifetime.alive) {
|
||||
lifetime.dispose();
|
||||
}
|
||||
}
|
||||
this._disposables.dispose();
|
||||
}
|
||||
}
|
||||
exports.Scope = Scope;
|
||||
//# sourceMappingURL=lifetime.js.map
|
||||
Reference in New Issue
Block a user