diff --git a/runtime/pointers.ts b/runtime/pointers.ts index 520c3f2c..86c9a8b7 100644 --- a/runtime/pointers.ts +++ b/runtime/pointers.ts @@ -572,7 +572,7 @@ export class PointerProperty extends Ref { * @returns */ public static get>(parent: Parent|Pointer, key: Key, leak_js_properties = false): PointerProperty ? MV : Parent[Key&keyof Parent]> { - + console.warn("getpp",parent,key) if (Pointer.isRef(key)) throw new Error("Cannot use a reference as a pointer property key"); let pointer:Pointer; @@ -588,7 +588,13 @@ export class PointerProperty extends Ref { // get current pointer property public override get val():T { // this.handleBeforePrimitiveValueGet(); - return this.pointer.getProperty(this.key, this.#leak_js_properties); + const val = this.pointer.getProperty(this.key, this.#leak_js_properties); + if (this.pointer instanceof LazyPointer) return "lazy..." + else if (val === NOT_EXISTING) { + console.log(this) + throw new Error(`Property ${this.key} does not exist in ${this.pointer}`); + } + else return val; } public override get current_val():T { @@ -2292,10 +2298,7 @@ export class Pointer extends Ref { this.val = v; return this; } - } - - - + } override get val():T { if (this.#garbage_collected) throw new PointerError("Pointer was garbage collected"); @@ -2303,7 +2306,7 @@ export class Pointer extends Ref { throw new PointerError("Cannot get value of uninitialized pointer") } // deref and check if not garbage collected - if (!this.is_persistent && !this.is_js_primitive && super.val instanceof WeakRef) { + if (!this.is_persistent && !this.is_js_primitive && super.val instanceof WeakRef && this.type !== Type.std.WeakRef) { const val = super.val.deref(); // seems to be garbage collected if (val === undefined && this.#loaded && !this.#is_js_primitive) { @@ -2331,7 +2334,7 @@ export class Pointer extends Ref { throw new PointerError("Cannot get value of uninitialized pointer") } // deref and check if not garbage collected - if (!this.is_persistent && !this.is_js_primitive && super.current_val instanceof WeakRef) { + if (!this.is_persistent && !this.is_js_primitive && super.current_val instanceof WeakRef && this.type !== Type.std.WeakRef) { const val = super.current_val.deref(); // seems to be garbage collected if (val === undefined && this.#loaded && !this.#is_js_primitive) { @@ -3406,7 +3409,7 @@ export class Pointer extends Ref { const res = JSInterface.createProxy(obj, this, this.type); if (res != INVALID && res != NOT_EXISTING) return res; // proxy created successfully - if (typeof obj == "symbol" || obj instanceof Stream || obj instanceof DatexFunction || obj instanceof JSTransferableFunction) { // no proxy needed?! + if (typeof obj == "symbol" || obj instanceof WeakRef || obj instanceof Stream || obj instanceof DatexFunction || obj instanceof JSTransferableFunction) { // no proxy needed?! return obj; } diff --git a/runtime/runtime.ts b/runtime/runtime.ts index ee757304..7cf2bc1b 100644 --- a/runtime/runtime.ts +++ b/runtime/runtime.ts @@ -1948,6 +1948,7 @@ export class Runtime { } let scope_map = sender_map?.get(sid); + // this is the next block or the only block (immediately closed) if (!scope_map || (scope_map.next == header.inc)) { @@ -2224,7 +2225,6 @@ export class Runtime { let old_type = Type.ofValue(value); let old_value = value instanceof UnresolvedValue ? value[DX_VALUE] : value; - // already the right type if (old_type == type) return old_value; @@ -2232,6 +2232,7 @@ export class Runtime { // only handle std namespace / js:Object / js:Symbol if (type.namespace == "std" || type == Type.js.NativeObject || type == Type.js.Symbol) { + const uncollapsed_old_value = old_value if (old_value instanceof Pointer) old_value = old_value.val; // handle default casts @@ -2431,6 +2432,31 @@ export class Runtime { break; } + case Type.std.WeakRef: { + if (old_value === VOID) { + // empty weakref + new_value = new WeakRef(Symbol("EMPTY")); + new_value.deref = ()=>{}; + } + else if (typeof uncollapsed_old_value == "symbol" || typeof uncollapsed_old_value == "object" || typeof uncollapsed_old_value == "function") { + const ptr = Pointer.collapseValue(Pointer.createOrGet(uncollapsed_old_value)) + new_value = new WeakRef(ptr); + } + // pointer id -> resolve pointer + else if (typeof old_value == "string" && old_value.startsWith("$")) { + try { + const ptr = Pointer.collapseValue(await Pointer.load(old_value.slice(1))) + new_value = new WeakRef(ptr); + } + catch { + // pointer not found, empty weakref + new_value = new WeakRef(Symbol("EMPTY")); + new_value.deref = ()=>{}; + } + } + else new_value = INVALID; + break; + } case Type.std.time: { if (old_value === VOID) new_value = new Time(Date.now()); @@ -2627,6 +2653,16 @@ export class Runtime { // symbol if (typeof value == "symbol") return value.toString().slice(7,-1) || undefined + + // weakref + if (value instanceof WeakRef) { + const deref = value.deref(); + // empty weak ref + if (!deref) return VOID; + const ptr = Pointer.createOrGet(deref) + if (ptr) return "$"+ptr.id; + else throw new TypeError("Cannot serialize weakref to non-pointer value"); + } // directly return, cannot be overwritten if (value === VOID || value === null || value instanceof Endpoint || value instanceof Type) return value; diff --git a/types/addressing.ts b/types/addressing.ts index e31efd42..eeadabd7 100644 --- a/types/addressing.ts +++ b/types/addressing.ts @@ -410,7 +410,14 @@ export class Endpoint extends Target { // max allowed time for DATEX online ping response - static max_ping_response_time = 1000; + static max_ping_response_time = 2000; + static max_ping_response_time_unyt_node = 5000; + static unyt_nodes = [ + "@+unyt1", + "@+unyt2", + "@+unyt3" + ] + // online state cache reload time if currently online/offline static cache_life_offline = 3_000; static cache_life_online = 15_000; @@ -445,11 +452,23 @@ export class Endpoint extends Target { try { // ping - await Runtime.datexOut(['"ping"', [], {sign:false, encrypt:false}], this, undefined, true, false, undefined, false, undefined, Endpoint.max_ping_response_time); + await Runtime.datexOut( + ['"ping"', [], {sign:false, encrypt:false}], + this, + undefined, + true, + false, + undefined, + false, + undefined, + Endpoint.unyt_nodes.includes(this.main.toString()) ? + Endpoint.max_ping_response_time_unyt_node : + Endpoint.max_ping_response_time + ); resolve_online!(this.#current_online = true) } // could not reach endpoint - catch { + catch (e) { resolve_online!(this.#current_online = false) } diff --git a/types/type.ts b/types/type.ts index d590873b..cc28620f 100644 --- a/types/type.ts +++ b/types/type.ts @@ -784,6 +784,8 @@ export class Type extends ExtensibleFunction { if (value instanceof Disjunction) return >Type.std.Disjunction; if (value instanceof Negation) return >Type.std.Negation; + if (value instanceof WeakRef) return >Type.std.WeakRef; + // get type from DX_TYPE property if (value?.[DX_TYPE]) return value[DX_TYPE]; @@ -879,6 +881,7 @@ export class Type extends ExtensibleFunction { if (_forClass == Number || Number.isPrototypeOf(_forClass)) return >Type.std.decimal; if (_forClass == globalThis.Boolean || globalThis.Boolean.isPrototypeOf(_forClass)) return >Type.std.boolean; if (_forClass == Symbol || Symbol.isPrototypeOf(_forClass)) return >Type.js.Symbol; + if (_forClass == WeakRef || WeakRef.isPrototypeOf(_forClass)) return >Type.std.WeakRef; if (_forClass == ArrayBuffer || TypedArray.isPrototypeOf(_forClass)) return >Type.std.buffer; if (_forClass == Tuple || Tuple.isPrototypeOf(_forClass)) return >Type.std.Tuple; @@ -1032,6 +1035,8 @@ export class Type extends ExtensibleFunction { SecurityError: Type.get("std:DatexSecurityError"), AssertionError: Type.get("std:AssertionError"), + WeakRef: Type.get("std:WeakRef"), + Scope: Type.get("std:Scope"), Debugger: Type.get("std:Debugger"),