using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using static Python.Runtime.Runtime;
namespace Python.Runtime
{
public static class RuntimeData
{
private static Type _formatterType;
public static Type FormatterType
{
get => _formatterType;
set
{
if (!typeof(IFormatter).IsAssignableFrom(value))
{
throw new ArgumentException("Not a type implemented IFormatter");
}
_formatterType = value;
}
}
public static ICLRObjectStorer WrappersStorer { get; set; }
///
/// Clears the old "clr_data" entry if a previous one is present.
///
static void ClearCLRData ()
{
BorrowedReference capsule = PySys_GetObject("clr_data");
if (!capsule.IsNull)
{
IntPtr oldData = PyCapsule_GetPointer(capsule, null);
PyMem_Free(oldData);
PyCapsule_SetPointer(capsule, IntPtr.Zero);
}
}
internal static void Stash()
{
var metaStorage = new RuntimeDataStorage();
MetaType.SaveRuntimeData(metaStorage);
var importStorage = new RuntimeDataStorage();
ImportHook.SaveRuntimeData(importStorage);
var typeStorage = new RuntimeDataStorage();
TypeManager.SaveRuntimeData(typeStorage);
var clsStorage = new RuntimeDataStorage();
ClassManager.SaveRuntimeData(clsStorage);
var moduleStorage = new RuntimeDataStorage();
SaveRuntimeDataModules(moduleStorage);
var objStorage = new RuntimeDataStorage();
SaveRuntimeDataObjects(objStorage);
var runtimeStorage = new RuntimeDataStorage();
runtimeStorage.AddValue("meta", metaStorage);
runtimeStorage.AddValue("import", importStorage);
runtimeStorage.AddValue("types", typeStorage);
runtimeStorage.AddValue("classes", clsStorage);
runtimeStorage.AddValue("modules", moduleStorage);
runtimeStorage.AddValue("objs", objStorage);
IFormatter formatter = CreateFormatter();
var ms = new MemoryStream();
formatter.Serialize(ms, runtimeStorage);
Debug.Assert(ms.Length <= int.MaxValue);
byte[] data = ms.GetBuffer();
// TODO: use buffer api instead
IntPtr mem = PyMem_Malloc(ms.Length + IntPtr.Size);
Marshal.WriteIntPtr(mem, (IntPtr)ms.Length);
Marshal.Copy(data, 0, mem + IntPtr.Size, (int)ms.Length);
ClearCLRData();
NewReference capsule = PyCapsule_New(mem, null, IntPtr.Zero);
PySys_SetObject("clr_data", capsule.DangerousGetAddress());
// Let the dictionary own the reference
capsule.Dispose();
}
internal static void RestoreRuntimeData()
{
try
{
RestoreRuntimeDataImpl();
}
finally
{
ClearStash();
}
}
private static void RestoreRuntimeDataImpl()
{
BorrowedReference capsule = PySys_GetObject("clr_data");
if (capsule.IsNull)
{
return;
}
IntPtr mem = PyCapsule_GetPointer(capsule, null);
int length = (int)Marshal.ReadIntPtr(mem);
byte[] data = new byte[length];
Marshal.Copy(mem + IntPtr.Size, data, 0, length);
var ms = new MemoryStream(data);
var formatter = CreateFormatter();
var storage = (RuntimeDataStorage)formatter.Deserialize(ms);
var objs = RestoreRuntimeDataObjects(storage.GetStorage("objs"));
RestoreRuntimeDataModules(storage.GetStorage("modules"));
var clsObjs = ClassManager.RestoreRuntimeData(storage.GetStorage("classes"));
TypeManager.RestoreRuntimeData(storage.GetStorage("types"));
ImportHook.RestoreRuntimeData(storage.GetStorage("import"));
PyCLRMetaType = MetaType.RestoreRuntimeData(storage.GetStorage("meta"));
foreach (var item in objs)
{
item.Value.ExecutePostActions();
XDecref(item.Key.pyHandle);
}
foreach (var item in clsObjs)
{
item.Value.ExecutePostActions();
}
}
public static bool HasStashData()
{
return !PySys_GetObject("clr_data").IsNull;
}
public static void ClearStash()
{
PySys_SetObject("clr_data", IntPtr.Zero);
}
static bool CheckSerializable (object o)
{
Type type = o.GetType();
do
{
if (!type.IsSerializable)
{
return false;
}
} while ((type = type.BaseType) != null);
return true;
}
private static void SaveRuntimeDataObjects(RuntimeDataStorage storage)
{
var objs = ManagedType.GetManagedObjects();
var extensionObjs = new List();
var wrappers = new Dictionary