-
Notifications
You must be signed in to change notification settings - Fork 774
Expand file tree
/
Copy pathReflectedClrType.cs
More file actions
129 lines (104 loc) · 4.41 KB
/
ReflectedClrType.cs
File metadata and controls
129 lines (104 loc) · 4.41 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
122
123
124
125
126
127
128
129
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) { }
internal ReflectedClrType(BorrowedReference original) : base(original) { }
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.
/// </remarks>
public static ReflectedClrType GetOrCreate(Type type)
{
if (ClassManager.cache.TryGetValue(type, out var pyType))
{
return pyType;
}
try
{
// 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);
}
catch (Exception e)
{
throw new InternalPythonnetException($"Failed to create Python type for {type.FullName}", e);
}
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, IList<Type> interfaces,
string name, string? assembly, string? ns,
BorrowedReference dict)
{
try
{
Type subType = ClassDerivedObject.CreateDerivedType(name,
baseClass.type.Value,
interfaces,
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) => rawPtr == other?.DangerousGetAddressOrNull();
public override int GetHashCode() => rawPtr.GetHashCode();
}