Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 58 additions & 7 deletions packages/kernel/src/dummyMeterControl.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,51 @@
import { assert } from '@endo/errors';

/* eslint-disable jsdoc/require-jsdoc */
import type { MeterControl } from './ag-types.js';

export function makeDummyMeterControl(): unknown {
/**
* Liveslots must be given a MeterControl object so it can turn metering on and
* off in metered execution environments. We have no metering, so this produces
* an object that obeys the MeterControl API but doesn't actually do anything.
*
* @returns a dummy MeterControl object.
*/
export function makeDummyMeterControl(): MeterControl {
/** Depth of metering disablement */
let meteringDisabled = 0;

/**
* Test if metering is disabled.
*
* @returns true iff metering is currently off.
*/
function isMeteringDisabled(): boolean {
return Boolean(meteringDisabled);
return meteringDisabled > 0;
}

/**
* Require metering to be on.
*
* @param message - Error message to throw if metering is off.
*/
function assertIsMetered(message: string): void {
assert(!meteringDisabled, message);
assert(meteringDisabled === 0, message);
}

/**
* Require metering to be off.
*
* @param message - Error message to throw if metering is on.
*/
function assertNotMetered(message: string): void {
assert(Boolean(meteringDisabled), message);
assert(meteringDisabled > 0, message);
}

/**
* Execute a thunk with metering off.
*
* @param thunk - The thunk to execute.
* @returns whatever `thunk` returns.
*/
function runWithoutMetering(thunk: () => unknown): unknown {
meteringDisabled += 1;
try {
Expand All @@ -26,6 +55,12 @@ export function makeDummyMeterControl(): unknown {
}
}

/**
* Execute an aynchronous thunk with metering off.
*
* @param thunk - The thunk to execute.
* @returns a promise for whatever `thunk` returns.
*/
async function runWithoutMeteringAsync(
thunk: () => unknown,
): Promise<unknown> {
Expand All @@ -37,8 +72,24 @@ export function makeDummyMeterControl(): unknown {
});
}

// return a version of func that runs outside metering
function unmetered(func: (...args: unknown[]) => unknown): unknown {
/**
* Return a version of func that runs outside metering. Since we have no
* metering, everything actually runs outside metering, so func itself would
* do, but we need to wrap it anyway to account for the nesting depth of
* metering disablement.
*
* @param func - The function to wrap.
* @returns A version of `func` that runs without being metered.
*/
function unmetered(
func: (...args: unknown[]) => unknown,
): (...args: unknown[]) => unknown {
/**
* A version of `func` with `runWithoutMetering` wrapped around it.
*
* @param args - The args to `func`.
* @returns whatever `func` returns.
*/
function wrapped(...args: unknown[]): unknown {
return runWithoutMetering(() => func(...args));
}
Expand Down
Loading