|
| 1 | +// ========================================================================== |
| 2 | +// This software is subject to the provisions of the Zope Public License, |
| 3 | +// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. |
| 4 | +// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED |
| 5 | +// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
| 6 | +// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS |
| 7 | +// FOR A PARTICULAR PURPOSE. |
| 8 | +// ========================================================================== |
| 9 | + |
| 10 | +using System; |
| 11 | +using System.Reflection; |
| 12 | + |
| 13 | +namespace Python.Runtime { |
| 14 | + |
| 15 | + /// <summary> |
| 16 | + /// Implements a Python type that wraps a CLR ctor call. Constructor objects |
| 17 | + /// support a .Overloads[] syntax to allow explicit ctor overload selection. |
| 18 | + /// </summary> |
| 19 | + /// <remarks> |
| 20 | + /// ClassManager stores a ConstructorBinding instance in the class's __dict__['Overloads'] |
| 21 | + /// |
| 22 | + /// SomeType.Overloads[Type, ...] works like this: |
| 23 | + /// 1) Python retreives the Overloads attribute from this ClassObject's dictionary normally |
| 24 | + /// and finds a non-null tp_descr_get slot which is called by the interpreter |
| 25 | + /// and returns an IncRef()ed pyHandle to itself. |
| 26 | + /// 2) The ConstructorBinding object handles the [] syntax in its mp_subscript by matching |
| 27 | + /// the Type object parameters to a contructor overload using Type.GetConstructor() |
| 28 | + /// [NOTE: I don't know why method overloads are not searched the same way.] |
| 29 | + /// and creating the BoundContructor oject which contains ContructorInfo object. |
| 30 | + /// 3) In tp_call, if ctorInfo is not null, ctorBinder.InvokeRaw() is called. |
| 31 | + /// </remarks> |
| 32 | + internal class ConstructorBinding : ExtensionType |
| 33 | + { |
| 34 | + Type type; // The managed Type being wrapped in a ClassObject |
| 35 | + IntPtr pyTypeHndl; // The python type tells GetInstHandle which Type to create. |
| 36 | + ConstructorBinder ctorBinder; |
| 37 | + IntPtr repr; |
| 38 | + |
| 39 | + public ConstructorBinding(Type type, IntPtr pyTypeHndl, ConstructorBinder ctorBinder) : base() { |
| 40 | + this.type = type; |
| 41 | + Runtime.Incref(pyTypeHndl); |
| 42 | + this.pyTypeHndl = pyTypeHndl; |
| 43 | + this.ctorBinder = ctorBinder; |
| 44 | + repr = IntPtr.Zero; |
| 45 | + } |
| 46 | + |
| 47 | + /// <summary> |
| 48 | + /// Descriptor __get__ implementation. |
| 49 | + /// Implements a Python type that wraps a CLR ctor call that requires the use |
| 50 | + /// of a .Overloads[pyTypeOrType...] syntax to allow explicit ctor overload |
| 51 | + /// selection. |
| 52 | + /// </summary> |
| 53 | + /// <param name="op"> PyObject* to a Constructors wrapper </param> |
| 54 | + /// <param name="instance"> the instance that the attribute was accessed through, |
| 55 | + /// or None when the attribute is accessed through the owner </param> |
| 56 | + /// <param name="owner"> always the owner class </param> |
| 57 | + /// <returns> a CtorMapper (that borrows a reference to this python type and the |
| 58 | + /// ClassObject's ConstructorBinder) wrapper. </returns> |
| 59 | + /// |
| 60 | + /// <remarks> |
| 61 | + /// Python 2.6.5 docs: |
| 62 | + /// object.__get__(self, instance, owner) |
| 63 | + /// Called to get the attribute of the owner class (class attribute access) |
| 64 | + /// or of an instance of that class (instance attribute access). |
| 65 | + /// owner is always the owner class, while instance is the instance that |
| 66 | + /// the attribute was accessed through, or None when the attribute is accessed through the owner. |
| 67 | + /// This method should return the (computed) attribute value or raise an AttributeError exception. |
| 68 | + /// </remarks> |
| 69 | + public static IntPtr tp_descr_get(IntPtr op, IntPtr instance, IntPtr owner) |
| 70 | + { |
| 71 | + ConstructorBinding self = (ConstructorBinding)GetManagedObject(op); |
| 72 | + if (self == null) { |
| 73 | + return IntPtr.Zero; |
| 74 | + } |
| 75 | + |
| 76 | + // It doesn't seem to matter if it's accessed through an instance (rather than via the type). |
| 77 | + /*if (instance != IntPtr.Zero) { |
| 78 | + // This is ugly! PyObject_IsInstance() returns 1 for true, 0 for false, -1 for error... |
| 79 | + if (Runtime.PyObject_IsInstance(instance, owner) < 1) { |
| 80 | + return Exceptions.RaiseTypeError("How in the world could that happen!"); |
| 81 | + } |
| 82 | + }*/ |
| 83 | + /* Since ExtensionType calls Runtime.PyObject_GC_UnTrack(py), don't |
| 84 | + Runtime.Incref(self.pyHandle); // Decref'd by the interpreter??? */ |
| 85 | + return self.pyHandle; |
| 86 | + } |
| 87 | + |
| 88 | + //==================================================================== |
| 89 | + // Implement explicit overload selection using subscript syntax ([]). |
| 90 | + //==================================================================== |
| 91 | + /// <summary> |
| 92 | + /// ConstructorBinding.GetItem(PyObject *o, PyObject *key) |
| 93 | + /// Return element of o corresponding to the object key or NULL on failure. |
| 94 | + /// This is the equivalent of the Python expression o[key]. |
| 95 | + /// </summary> |
| 96 | + /// <param name="tp"></param> |
| 97 | + /// <param name="idx"></param> |
| 98 | + /// <returns></returns> |
| 99 | + public static IntPtr mp_subscript(IntPtr op, IntPtr key) { |
| 100 | + ConstructorBinding self = (ConstructorBinding)GetManagedObject(op); |
| 101 | + |
| 102 | + Type[] types = Runtime.PythonArgsToTypeArray(key); |
| 103 | + if (types == null) { |
| 104 | + return Exceptions.RaiseTypeError("type(s) expected"); |
| 105 | + } |
| 106 | + //MethodBase[] methBaseArray = self.ctorBinder.GetMethods(); |
| 107 | + //MethodBase ci = MatchSignature(methBaseArray, types); |
| 108 | + ConstructorInfo ci = self.type.GetConstructor(types); |
| 109 | + if (ci == null) { |
| 110 | + string msg = "No match found for constructor signature"; |
| 111 | + return Exceptions.RaiseTypeError(msg); |
| 112 | + } |
| 113 | + BoundContructor boundCtor = new BoundContructor(self.type, self.pyTypeHndl, self.ctorBinder, ci); |
| 114 | + |
| 115 | + /* Since ExtensionType calls Runtime.PyObject_GC_UnTrack(py), don't |
| 116 | + Runtime.Incref(boundCtor.pyHandle); // Decref'd by the interpreter??? */ |
| 117 | + return boundCtor.pyHandle; |
| 118 | + } |
| 119 | + |
| 120 | + //==================================================================== |
| 121 | + // ConstructorBinding __repr__ implementation [borrowed from MethodObject]. |
| 122 | + //==================================================================== |
| 123 | + |
| 124 | + public static IntPtr tp_repr(IntPtr ob) { |
| 125 | + ConstructorBinding self = (ConstructorBinding)GetManagedObject(ob); |
| 126 | + if (self.repr != IntPtr.Zero) { |
| 127 | + Runtime.Incref(self.repr); |
| 128 | + return self.repr; |
| 129 | + } |
| 130 | + MethodBase[] methods = self.ctorBinder.GetMethods(); |
| 131 | + string name = self.type.Name; |
| 132 | + string doc = ""; |
| 133 | + for (int i = 0; i < methods.Length; i++) { |
| 134 | + if (doc.Length > 0) |
| 135 | + doc += "\n"; |
| 136 | + string str = methods[i].ToString(); |
| 137 | + int idx = str.IndexOf("("); |
| 138 | + doc += String.Format("{0}{1}", name, str.Substring(idx)); |
| 139 | + } |
| 140 | + self.repr = Runtime.PyString_FromString(doc); |
| 141 | + Runtime.Incref(self.repr); |
| 142 | + return self.repr; |
| 143 | + } |
| 144 | + |
| 145 | + //==================================================================== |
| 146 | + // ConstructorBinding dealloc implementation. |
| 147 | + //==================================================================== |
| 148 | + |
| 149 | + public static new void tp_dealloc(IntPtr ob) { |
| 150 | + ConstructorBinding self = (ConstructorBinding)GetManagedObject(ob); |
| 151 | + Runtime.Decref(self.repr); |
| 152 | + Runtime.Decref(self.pyTypeHndl); |
| 153 | + ExtensionType.FinalizeObject(self); |
| 154 | + } |
| 155 | + } |
| 156 | + |
| 157 | + /// <summary> |
| 158 | + /// Implements a Python type that constucts the given Type given a particular ContructorInfo. |
| 159 | + /// </summary> |
| 160 | + /// <remarks> |
| 161 | + /// Here mostly because I wanted a new __repr__ function for the selected constructor. |
| 162 | + /// An earlier implementation hung the __call__ on the ContructorBinding class and |
| 163 | + /// returned an Incref()ed self.pyHandle from the __get__ function. |
| 164 | + /// </remarks> |
| 165 | + internal class BoundContructor : ExtensionType { |
| 166 | + Type type; // The managed Type being wrapped in a ClassObject |
| 167 | + IntPtr pyTypeHndl; // The python type tells GetInstHandle which Type to create. |
| 168 | + ConstructorBinder ctorBinder; |
| 169 | + ConstructorInfo ctorInfo; |
| 170 | + IntPtr repr; |
| 171 | + |
| 172 | + public BoundContructor(Type type, IntPtr pyTypeHndl, ConstructorBinder ctorBinder, ConstructorInfo ci) |
| 173 | + : base() { |
| 174 | + this.type = type; |
| 175 | + Runtime.Incref(pyTypeHndl); |
| 176 | + this.pyTypeHndl = pyTypeHndl; |
| 177 | + this.ctorBinder = ctorBinder; |
| 178 | + ctorInfo = ci; |
| 179 | + repr = IntPtr.Zero; |
| 180 | + } |
| 181 | + |
| 182 | + /// <summary> |
| 183 | + /// BoundContructor.__call__(PyObject *callable_object, PyObject *args, PyObject *kw) |
| 184 | + /// </summary> |
| 185 | + /// <param name="ob"> PyObject *callable_object </param> |
| 186 | + /// <param name="args"> PyObject *args </param> |
| 187 | + /// <param name="kw"> PyObject *kw </param> |
| 188 | + /// <returns> A reference to a new instance of the class by invoking the selected ctor(). </returns> |
| 189 | + public static IntPtr tp_call(IntPtr op, IntPtr args, IntPtr kw) { |
| 190 | + BoundContructor self = (BoundContructor)GetManagedObject(op); |
| 191 | + // Even though a call with null ctorInfo just produces the old behavior |
| 192 | + /*if (self.ctorInfo == null) { |
| 193 | + string msg = "Usage: Class.Overloads[CLR_or_python_Type, ...]"; |
| 194 | + return Exceptions.RaiseTypeError(msg); |
| 195 | + }*/ |
| 196 | + // Bind using ConstructorBinder.Bind and invoke the ctor providing a null instancePtr |
| 197 | + // which will fire self.ctorInfo using ConstructorInfo.Invoke(). |
| 198 | + Object obj = self.ctorBinder.InvokeRaw(IntPtr.Zero, args, kw, self.ctorInfo); |
| 199 | + if (obj == null) { |
| 200 | + // XXX set an error |
| 201 | + return IntPtr.Zero; |
| 202 | + } |
| 203 | + // Instantiate the python object that wraps the result of the method call |
| 204 | + // and return the PyObject* to it. |
| 205 | + return CLRObject.GetInstHandle(obj, self.pyTypeHndl); |
| 206 | + } |
| 207 | + |
| 208 | + //==================================================================== |
| 209 | + // BoundContructor __repr__ implementation [borrowed from MethodObject]. |
| 210 | + //==================================================================== |
| 211 | + |
| 212 | + public static IntPtr tp_repr(IntPtr ob) { |
| 213 | + BoundContructor self = (BoundContructor)GetManagedObject(ob); |
| 214 | + if (self.repr != IntPtr.Zero) { |
| 215 | + Runtime.Incref(self.repr); |
| 216 | + return self.repr; |
| 217 | + } |
| 218 | + string name = self.type.FullName; |
| 219 | + string str = self.ctorInfo.ToString(); |
| 220 | + int idx = str.IndexOf("("); |
| 221 | + str = String.Format("returns a new {0}{1}", name, str.Substring(idx)); |
| 222 | + self.repr = Runtime.PyString_FromString(str); |
| 223 | + Runtime.Incref(self.repr); |
| 224 | + return self.repr; |
| 225 | + } |
| 226 | + |
| 227 | + //==================================================================== |
| 228 | + // ConstructorBinding dealloc implementation. |
| 229 | + //==================================================================== |
| 230 | + |
| 231 | + public static new void tp_dealloc(IntPtr ob) { |
| 232 | + BoundContructor self = (BoundContructor)GetManagedObject(ob); |
| 233 | + Runtime.Decref(self.repr); |
| 234 | + Runtime.Decref(self.pyTypeHndl); |
| 235 | + ExtensionType.FinalizeObject(self); |
| 236 | + } |
| 237 | + } |
| 238 | +} |
0 commit comments