Skip to content

Commit

Permalink
Merge pull request #60 from unyt-org/feat-weak-refs
Browse files Browse the repository at this point in the history
Add WeakRef support for DATEX
  • Loading branch information
benStre authored Jan 24, 2024
2 parents 04f6e0f + 1e83aad commit a135ede
Show file tree
Hide file tree
Showing 4 changed files with 76 additions and 13 deletions.
21 changes: 12 additions & 9 deletions runtime/pointers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -572,7 +572,7 @@ export class PointerProperty<T=any> extends Ref<T> {
* @returns
*/
public static get<const Key, Parent extends PointerPropertyParent<Key,unknown>>(parent: Parent|Pointer<Parent>, key: Key, leak_js_properties = false): PointerProperty<Parent extends Map<unknown, infer MV> ? 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;
Expand All @@ -588,7 +588,13 @@ export class PointerProperty<T=any> extends Ref<T> {
// 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 {
Expand Down Expand Up @@ -2292,18 +2298,15 @@ export class Pointer<T = any> extends Ref<T> {
this.val = <any>v;
return <any>this;
}
}



}

override get val():T {
if (this.#garbage_collected) throw new PointerError("Pointer was garbage collected");
else if (!this.#loaded) {
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) {
Expand Down Expand Up @@ -2331,7 +2334,7 @@ export class Pointer<T = any> extends Ref<T> {
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) {
Expand Down Expand Up @@ -3406,7 +3409,7 @@ export class Pointer<T = any> extends Ref<T> {
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;
}

Expand Down
38 changes: 37 additions & 1 deletion runtime/runtime.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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)) {

Expand Down Expand Up @@ -2224,14 +2225,14 @@ 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;

let new_value:any = UNKNOWN_TYPE;

// 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
Expand Down Expand Up @@ -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());
Expand Down Expand Up @@ -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;
Expand Down
25 changes: 22 additions & 3 deletions types/addressing.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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)
}

Expand Down
5 changes: 5 additions & 0 deletions types/type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -784,6 +784,8 @@ export class Type<T = any> extends ExtensibleFunction {
if (value instanceof Disjunction) return <Type<T>>Type.std.Disjunction;
if (value instanceof Negation) return <Type<T>>Type.std.Negation;

if (value instanceof WeakRef) return <Type<T>>Type.std.WeakRef;

// get type from DX_TYPE property
if (value?.[DX_TYPE]) return value[DX_TYPE];

Expand Down Expand Up @@ -879,6 +881,7 @@ export class Type<T = any> extends ExtensibleFunction {
if (_forClass == Number || Number.isPrototypeOf(_forClass)) return <Type<T>>Type.std.decimal;
if (_forClass == globalThis.Boolean || globalThis.Boolean.isPrototypeOf(_forClass)) return <Type<T>>Type.std.boolean;
if (_forClass == Symbol || Symbol.isPrototypeOf(_forClass)) return <Type<T>>Type.js.Symbol;
if (_forClass == WeakRef || WeakRef.isPrototypeOf(_forClass)) return <Type<T>>Type.std.WeakRef;

if (_forClass == ArrayBuffer || TypedArray.isPrototypeOf(_forClass)) return <Type<T>>Type.std.buffer;
if (_forClass == Tuple || Tuple.isPrototypeOf(_forClass)) return <Type<T>>Type.std.Tuple;
Expand Down Expand Up @@ -1032,6 +1035,8 @@ export class Type<T = any> extends ExtensibleFunction {
SecurityError: Type.get("std:DatexSecurityError"),
AssertionError: Type.get("std:AssertionError"),

WeakRef: Type.get("std:WeakRef"),

Scope: Type.get<Scope>("std:Scope"),

Debugger: Type.get<Debugger>("std:Debugger"),
Expand Down

0 comments on commit a135ede

Please sign in to comment.