Skip to content

Commit

Permalink
fix js:Function with lazy pointers, lazy pointer init
Browse files Browse the repository at this point in the history
  • Loading branch information
benStre committed Dec 9, 2023
1 parent 069074a commit b8e7a38
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 22 deletions.
10 changes: 8 additions & 2 deletions runtime/pointers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2119,7 +2119,13 @@ export class Pointer<T = any> extends Ref<T> {
this.id = id ?? Pointer.getUniquePointerID(this) // set id
this.#is_placeholder = false; // after id change
// first time actual visible pointer
for (let l of Pointer.pointer_add_listeners) l(this);
for (const l of Pointer.pointer_add_listeners) l(this);
// pointer for id listeners
if (Pointer.pointer_for_id_created_listeners.has(this.id)) {
for (const l of Pointer.pointer_for_id_created_listeners.get(this.id)!) l(this);
Pointer.pointer_for_id_created_listeners.delete(this.id)
}

}

// set id if not set initially set
Expand All @@ -2129,6 +2135,7 @@ export class Pointer<T = any> extends Ref<T> {
// if (!this.is_placeholder && this.id !== undefined && !Pointer.#local_pointers.has(this)) {
// // console.log("TODO: pointer transfer map")
// }
// is id transfer for placeholder, trigger value init

if (typeof id == "string") {
// convert string to buffer
Expand Down Expand Up @@ -2271,7 +2278,6 @@ export class Pointer<T = any> extends Ref<T> {
* @param v initial value
*/
protected initializeValue(v:RefOrValue<T>, is_transform?:boolean) {

let val = Ref.collapseValue(v,true,true);

if (typeof val == "symbol" && Symbol.keyFor(val) !== undefined) {
Expand Down
37 changes: 37 additions & 0 deletions types/function-utils.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { LazyPointer } from "../runtime/lazy-pointer.ts";
import { callWithMetadata, callWithMetadataAsync, getMeta } from "../utils/caller_metadata.ts";
import { RuntimeError } from "./errors.ts";

Expand Down Expand Up @@ -134,12 +135,48 @@ const isArrowFunction = (fnSrc:string) => {
return !!fnSrc.match(/^(async\s+)?\([^)]*\)\s*=>/)
}

function resolveLazyDependencies(deps:Record<string,unknown>) {
for (const [key, value] of Object.entries(deps)) {
if (value instanceof LazyPointer) value.onLoad((v) => {
deps[key] = v
});
}
}

function assertLazyDependenciesResolved(deps:Record<string,unknown>) {
for (const [key, value] of Object.entries(deps)) {
// TODO non js-Function specific error
if (value instanceof LazyPointer) throw new Error("Cannot call <js:Function>, dependency variable '"+key+"' is not yet initialized")
}
}

/**
* Create a new function from JS source code with injected dependency variables
* Also resolves LazyPointer dependencies
* @param source
* @param dependencies
* @returns
*/
export function createFunctionWithDependencyInjectionsResolveLazyPointers(source: string, dependencies: Record<string, unknown>): ((...args:unknown[]) => unknown) {
let fn: Function|undefined;

const intermediateFn = (...args:any[]) => {
if (!fn) {
assertLazyDependenciesResolved(dependencies);
fn = createFunctionWithDependencyInjections(source, dependencies)
}
return fn(...args)
}
resolveLazyDependencies(dependencies)
return intermediateFn;
}

/**
* Create a new function from JS source code with injected dependency variables
* @param source
* @param dependencies
* @returns
* @deprecated use createFunctionWithDependencyInjectionsResolveLazyPointers
*/
export function createFunctionWithDependencyInjections(source: string, dependencies: Record<string, unknown>): ((...args:unknown[]) => unknown) {
const hasThis = Object.keys(dependencies).includes('this');
Expand Down
23 changes: 3 additions & 20 deletions types/js-function.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import { LazyPointer } from "../runtime/lazy-pointer.ts";
import { Pointer } from "../runtime/pointers.ts";
import { Runtime } from "../runtime/runtime.ts";
import { ExtensibleFunction, getDeclaredExternalVariables, getDeclaredExternalVariablesAsync, createFunctionWithDependencyInjections, getSourceWithoutUsingDeclaration, Callable } from "./function-utils.ts";
import { ExtensibleFunction, getDeclaredExternalVariables, getDeclaredExternalVariablesAsync, getSourceWithoutUsingDeclaration, Callable, createFunctionWithDependencyInjectionsResolveLazyPointers } from "./function-utils.ts";


export type JSTransferableFunctionOptions = {
Expand All @@ -32,32 +32,15 @@ export class JSTransferableFunction extends ExtensibleFunction {
if (origin !== Runtime.endpoint && !Runtime.trustedEndpoints.get(origin)?.includes("remote-js-execution")) {
throw new Error("Cannot execute js:Function, origin "+origin+" has no permission to execute js source code on this endpoint");
}
this.assertLazyDependenciesResolved();
if (this.deps.this) return intermediateFn.apply(this.deps.this, args)
else return intermediateFn(...args)
return intermediateFn(...args)
}
super(fn);
this.resolveLazyDependencies(); // make sure LazyPointer deps are resolved
this.#fn = fn;
}

this.source = source;
}

private resolveLazyDependencies() {
for (const [key, value] of Object.entries(this.deps)) {
if (value instanceof LazyPointer) value.onLoad((v) => this.deps[key] = v);
}
}

#resolved = false;
private assertLazyDependenciesResolved() {
if (this.#resolved) return true;
for (const [key, value] of Object.entries(this.deps)) {
if (value instanceof LazyPointer) throw new Error("Cannot call <js:Function>, dependency variable '"+key+"' is not yet initialized")
}
this.#resolved = true;
}

call(...args:any[]) {
return this.#fn(...args)
Expand Down Expand Up @@ -110,7 +93,7 @@ export class JSTransferableFunction extends ExtensibleFunction {
}

static #createTransferableFunction(source: string, dependencies: Record<string, unknown>, flags?: string[], options?:JSTransferableFunctionOptions) {
const intermediateFn = createFunctionWithDependencyInjections(source, dependencies);
const intermediateFn = createFunctionWithDependencyInjectionsResolveLazyPointers(source, dependencies);
return new JSTransferableFunction(intermediateFn, dependencies, source, flags, options);
}

Expand Down

0 comments on commit b8e7a38

Please sign in to comment.