qamp/Qrakhen.Qamp.Core/Values/Ptr.cs

82 lines
2.2 KiB
C#

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<T>(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<byte> 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();
}
}