forked from pythonnet/pythonnet
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathDelegateObject.cs
More file actions
129 lines (105 loc) · 4.13 KB
/
DelegateObject.cs
File metadata and controls
129 lines (105 loc) · 4.13 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;
namespace Python.Runtime
{
/// <summary>
/// Managed class that provides the implementation for reflected delegate
/// types. Delegates are represented in Python by generated type objects.
/// Each of those type objects is associated an instance of this class,
/// which provides its implementation.
/// </summary>
[Serializable]
internal class DelegateObject : ClassBase
{
private MethodBinder binder;
internal DelegateObject(Type tp) : base(tp)
{
binder = new MethodBinder(tp.GetMethod("Invoke"));
}
/// <summary>
/// Given a PyObject pointer to an instance of a delegate type, return
/// the true managed delegate the Python object represents (or null).
/// </summary>
private static Delegate? GetTrueDelegate(BorrowedReference op)
{
var o = GetManagedObject(op) as CLRObject;
if (o != null)
{
var d = o.inst as Delegate;
return d;
}
return null;
}
internal override bool CanSubclass()
{
return false;
}
/// <summary>
/// DelegateObject __new__ implementation. The result of this is a new
/// PyObject whose type is DelegateObject and whose ob_data is a handle
/// to an actual delegate instance. The method wrapped by the actual
/// delegate instance belongs to an object generated to relay the call
/// to the Python callable passed in.
/// </summary>
public static NewReference tp_new(BorrowedReference tp, BorrowedReference args, BorrowedReference kw)
{
var self = (DelegateObject)GetManagedObject(tp)!;
if (!self.type.Valid)
{
return Exceptions.RaiseTypeError(self.type.DeletedMessage);
}
Type type = self.type.Value;
if (Runtime.PyTuple_Size(args) != 1)
{
return Exceptions.RaiseTypeError("class takes exactly one argument");
}
BorrowedReference method = Runtime.PyTuple_GetItem(args, 0);
if (Runtime.PyCallable_Check(method) != 1)
{
return Exceptions.RaiseTypeError("argument must be callable");
}
Delegate d = PythonEngine.DelegateManager.GetDelegate(type, new PyObject(method));
return CLRObject.GetReference(d, ClassManager.GetClass(type));
}
/// <summary>
/// Implements __call__ for reflected delegate types.
/// </summary>
public static NewReference tp_call(BorrowedReference ob, BorrowedReference args, BorrowedReference kw)
{
// TODO: add fast type check!
BorrowedReference pytype = Runtime.PyObject_TYPE(ob);
var self = (DelegateObject)GetManagedObject(pytype)!;
var o = GetManagedObject(ob) as CLRObject;
if (o == null)
{
return Exceptions.RaiseTypeError("invalid argument");
}
var d = o.inst as Delegate;
if (d == null)
{
return Exceptions.RaiseTypeError("invalid argument");
}
return self.binder.Invoke(ob, args, kw);
}
/// <summary>
/// Implements __cmp__ for reflected delegate types.
/// </summary>
public new static NewReference tp_richcompare(BorrowedReference ob, BorrowedReference other, int op)
{
if (op != Runtime.Py_EQ && op != Runtime.Py_NE)
{
return new NewReference(Runtime.PyNotImplemented);
}
BorrowedReference pytrue = Runtime.PyTrue;
BorrowedReference pyfalse = Runtime.PyFalse;
// swap true and false for NE
if (op != Runtime.Py_EQ)
{
pytrue = Runtime.PyFalse;
pyfalse = Runtime.PyTrue;
}
Delegate? d1 = GetTrueDelegate(ob);
Delegate? d2 = GetTrueDelegate(other);
return new NewReference(d1 == d2 ? pytrue : pyfalse);
}
}
}