forked from pythonnet/pythonnet
-
Notifications
You must be signed in to change notification settings - Fork 31
Expand file tree
/
Copy pathReflectedClrType.cs
More file actions
121 lines (96 loc) · 4.14 KB
/
ReflectedClrType.cs
File metadata and controls
121 lines (96 loc) · 4.14 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.Serialization;
using static Python.Runtime.PythonException;
namespace Python.Runtime;
[Serializable]
internal sealed class ReflectedClrType : PyType
{
private ReflectedClrType(StolenReference reference) : base(reference, prevalidated: true) { }
internal ReflectedClrType(ReflectedClrType original) : base(original, prevalidated: true) { }
ReflectedClrType(SerializationInfo info, StreamingContext context) : base(info, context) { }
internal ClassBase Impl => (ClassBase)ManagedType.GetManagedObject(this)!;
/// <summary>
/// Get the Python type that reflects the given CLR type.
/// </summary>
/// <remarks>
/// Returned <see cref="ReflectedClrType"/> might be partially initialized.
/// If you need fully initialized type, use <see cref="GetOrInitialize(ClassBase, Type)"/>
/// </remarks>
public static ReflectedClrType GetOrCreate(Type type)
{
if (ClassManager.cache.TryGetValue(type, out var pyType))
{
return pyType;
}
// Ensure, that matching Python type exists first.
// It is required for self-referential classes
// (e.g. with members, that refer to the same class)
pyType = AllocateClass(type);
ClassManager.cache.Add(type, pyType);
var impl = ClassManager.CreateClass(type);
TypeManager.InitializeClassCore(type, pyType, impl);
ClassManager.InitClassBase(type, impl, pyType);
// Now we force initialize the Python type object to reflect the given
// managed type, filling the Python type slots with thunks that
// point to the managed methods providing the implementation.
TypeManager.InitializeClass(pyType, impl, type);
return pyType;
}
internal void Restore(Dictionary<string, object?> context)
{
var cb = (ClassBase)context["impl"]!;
Debug.Assert(cb is not null);
cb!.Load(this, context);
Restore(cb);
}
internal void Restore(ClassBase cb)
{
ClassManager.InitClassBase(cb.type.Value, cb, this);
TypeManager.InitializeClass(this, cb, cb.type.Value);
}
internal static NewReference CreateSubclass(ClassBase baseClass,
string name, string? assembly, string? ns,
BorrowedReference dict)
{
try
{
Type subType = ClassDerivedObject.CreateDerivedType(name,
baseClass.type.Value,
dict,
ns,
assembly);
var py_type = GetOrCreate(subType);
// by default the class dict will have all the C# methods in it, but as this is a
// derived class we want the python overrides in there instead if they exist.
var cls_dict = Util.ReadRef(py_type, TypeOffset.tp_dict);
ThrowIfIsNotZero(Runtime.PyDict_Update(cls_dict, dict));
// Update the __classcell__ if it exists
BorrowedReference cell = Runtime.PyDict_GetItemString(cls_dict, "__classcell__");
if (!cell.IsNull)
{
ThrowIfIsNotZero(Runtime.PyCell_Set(cell, py_type));
ThrowIfIsNotZero(Runtime.PyDict_DelItemString(cls_dict, "__classcell__"));
}
return new NewReference(py_type);
}
catch (Exception e)
{
return Exceptions.RaiseTypeError(e.Message);
}
}
static ReflectedClrType AllocateClass(Type clrType)
{
string name = TypeManager.GetPythonTypeName(clrType);
var type = TypeManager.AllocateTypeObject(name, Runtime.PyCLRMetaType);
type.Flags = TypeFlags.Default
| TypeFlags.HasClrInstance
| TypeFlags.HeapType
| TypeFlags.BaseType
| TypeFlags.HaveGC;
return new ReflectedClrType(type.Steal());
}
public override bool Equals(PyObject? other) => other != null && rawPtr == other.rawPtr;
public override int GetHashCode() => rawPtr.GetHashCode();
}