using Qrakhen.Qamp.Core.Values.Objects; using System.Runtime.InteropServices; using Qrakhen.Qamp.Core.Collections; namespace Qrakhen.Qamp.Core.Values; // generally interesting: GCHandle.ToIntPtr(GCHandle.Alloc(obj, GCHandleType.Normal)); [StructLayout(LayoutKind.Sequential, Size = sizeof(ulong))] public readonly struct Ptr { [Serialized] public readonly Address Address; public Obj? Value { get { if (ObjTable.Global.TryGet(Address, out Obj? obj)) return obj; return null; } } private Ptr(Address address) { Address = address; } public static Ptr Create(Obj obj) { return new Ptr(obj.__Address); } public T? As(bool throwWhenNull = true) where T : Obj { T? value = Value as T; if (value == null && throwWhenNull) throw new RuntimeException($"Could not convert Object {Value} to target type {typeof(T)}.", Value); return value; } public Obj? As(Type type, bool throwWhenNull = true) { Obj? value = Convert.ChangeType(Value, type) as Obj; if (value == null && throwWhenNull) throw new RuntimeException($"Could not convert Object {Value} to target type {type}.", Value); return value; } public override string ToString() => $"0x{Value}"; public static async Task __GC_Prepare() { await Task.Run(() => { foreach (var obj in ObjTable.Global.Entries) { obj.Value.__GC_Count = 0; } }); } public static byte[] SerializeFunctions() { List result = new(); foreach (var element in ObjTable.Global.Entries) { Obj obj = element.Value; if (obj == null || obj.__GC_Marked) continue; byte[] bytes; if (obj is Function function) { bytes = function.Serialize(); } else if (obj is Context context) { bytes = context.Function.Serialize(); } else { continue; } result.AddRange(((long)element.Key).GetBytes()); result.AddRange(bytes.Length.GetBytes()); result.AddRange(bytes); result.Add(0); } return result.ToArray(); } }