-
Notifications
You must be signed in to change notification settings - Fork 774
Expand file tree
/
Copy pathInterfaceObject.cs
More file actions
130 lines (112 loc) · 4.22 KB
/
InterfaceObject.cs
File metadata and controls
130 lines (112 loc) · 4.22 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
130
using System;
using System.Reflection;
using System.Runtime.InteropServices;
namespace Python.Runtime
{
/// <summary>
/// Provides the implementation for reflected interface types. Managed
/// interfaces are represented in Python by actual Python type objects.
/// Each of those type objects is associated with an instance of this
/// class, which provides the implementation for the Python type.
/// </summary>
[Serializable]
internal class InterfaceObject : ClassBase
{
[NonSerialized]
internal ConstructorInfo? ctor;
internal InterfaceObject(Type tp) : base(tp)
{
this.ctor = TryGetCOMConstructor(tp);
}
static ConstructorInfo? TryGetCOMConstructor(Type tp)
{
var comClass = (CoClassAttribute?)Attribute.GetCustomAttribute(tp, cc_attr);
return comClass?.CoClass.GetConstructor(Type.EmptyTypes);
}
private static readonly Type cc_attr;
static InterfaceObject()
{
cc_attr = typeof(CoClassAttribute);
}
/// <summary>
/// Implements __new__ for reflected interface types.
/// </summary>
public static NewReference tp_new(BorrowedReference tp, BorrowedReference args, BorrowedReference kw)
{
var self = (InterfaceObject)GetManagedObject(tp)!;
if (!self.type.Valid)
{
return Exceptions.RaiseTypeError(self.type.DeletedMessage);
}
var nargs = Runtime.PyTuple_Size(args);
Type type = self.type.Value;
object obj;
if (nargs == 1)
{
BorrowedReference inst = Runtime.PyTuple_GetItem(args, 0);
if (GetManagedObject(inst) is CLRObject co && type.IsInstanceOfType(co.inst))
{
obj = co.inst;
}
else
{
Exceptions.SetError(Exceptions.TypeError, $"object does not implement {type.Name}");
return default;
}
}
else if (nargs == 0 && self.ctor != null)
{
obj = self.ctor.Invoke(null);
if (obj == null || !type.IsInstanceOfType(obj))
{
Exceptions.SetError(Exceptions.TypeError, "CoClass default constructor failed");
return default;
}
}
else
{
Exceptions.SetError(Exceptions.TypeError, "interface takes exactly one argument");
return default;
}
return self.TryWrapObject(obj);
}
/// <summary>
/// Wrap the given object in an interface object, so that only methods
/// of the interface are available.
/// </summary>
public NewReference TryWrapObject(object impl)
=> this.type.Valid
? CLRObject.GetReference(impl, ClassManager.GetClass(this.type.Value))
: Exceptions.RaiseTypeError(this.type.DeletedMessage);
/// <summary>
/// Expose the wrapped implementation through attributes in both
/// converted/encoded (__implementation__) and raw (__raw_implementation__) form.
/// </summary>
public static NewReference tp_getattro(BorrowedReference ob, BorrowedReference key)
{
var clrObj = (CLRObject)GetManagedObject(ob)!;
if (!Runtime.PyString_Check(key))
{
return Exceptions.RaiseTypeError("string expected");
}
string? name = Runtime.GetManagedString(key);
if (name == "__implementation__")
{
return Converter.ToPython(clrObj.inst);
}
else if (name == "__raw_implementation__")
{
return CLRObject.GetReference(clrObj.inst);
}
return Runtime.PyObject_GenericGetAttr(ob, key);
}
protected override void OnDeserialization(object sender)
{
base.OnDeserialization(sender);
if (this.type.Valid)
{
this.ctor = TryGetCOMConstructor(this.type.Value);
}
}
}
}