[ Web Proxy ]
URL:
Viewing: https://raw.githubusercontent.com/laomagege/pythonnet/develop/src/runtime/methodbinding.cs [Back]  [Original]

// ==========================================================================
// This software is subject to the provisions of the Zope Public License,
// Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
// FOR A PARTICULAR PURPOSE.
// ==========================================================================

using System;
using System.Reflection;

namespace Python.Runtime {

    //========================================================================
    // Implements a Python binding type for CLR methods. These work much like
    // standard Python method bindings, but the same type is used to bind
    // both static and instance methods.
    //========================================================================

    internal class MethodBinding : ExtensionType {

        internal MethodInfo info;
        internal MethodObject m;
        internal IntPtr target;

        public MethodBinding(MethodObject m, IntPtr target) : base() {
            Runtime.Incref(target);
            this.target = target;
            this.info = null;
            this.m = m;
        }

         //====================================================================
         // Implement binding of generic methods using the subscript syntax [].
         //====================================================================
 
         public static IntPtr mp_subscript(IntPtr tp, IntPtr idx) {
             MethodBinding self = (MethodBinding)GetManagedObject(tp);

            Type[] types = Runtime.PythonArgsToTypeArray(idx);
            if (types == null) {
                 return Exceptions.RaiseTypeError("type(s) expected");
            }

             MethodInfo mi = MethodBinder.MatchParameters(self.m.info, types);
            if (mi == null) {
                string e = "No match found for given type params";
                return Exceptions.RaiseTypeError(e);
            }

             MethodBinding mb = new MethodBinding(self.m, self.target);
             mb.info = mi;
             Runtime.Incref(mb.pyHandle);
             return mb.pyHandle;            
         }


        //====================================================================
        // MethodBinding __getattribute__ implementation. 
        //====================================================================

        public static IntPtr tp_getattro(IntPtr ob, IntPtr key) {
            MethodBinding self = (MethodBinding)GetManagedObject(ob);

            if (!Runtime.PyString_Check(key)) {
                Exceptions.SetError(Exceptions.TypeError, "string expected");
                return IntPtr.Zero;
            }

            string name = Runtime.GetManagedString(key);
            if (name == "__doc__") {
                IntPtr doc = self.m.GetDocString();
                Runtime.Incref(doc);
                return doc;
            }

            // XXX deprecate __overloads__ soon...
            if (name == "__overloads__" || name == "Overloads") {
                OverloadMapper om = new OverloadMapper(self.m, self.target);
                Runtime.Incref(om.pyHandle);
                return om.pyHandle;            
            }

            return Runtime.PyObject_GenericGetAttr(ob, key);
        }


        //====================================================================
        // MethodBinding  __call__ implementation.
        //====================================================================

        public static IntPtr tp_call(IntPtr ob, IntPtr args, IntPtr kw) {
			MethodBinding self = (MethodBinding)GetManagedObject(ob);

			// This works around a situation where the wrong generic method is picked,
			// for example this method in the tests: string Overloaded(int arg1, int arg2, string arg3)
			if (self.info != null)
			{
				if (self.info.IsGenericMethod)
				{
					int len = Runtime.PyTuple_Size(args);
					Type[] sigTp = Runtime.PythonArgsToTypeArray(args, true);
					if (sigTp != null)
					{
						Type[] genericTp = self.info.GetGenericArguments();
						MethodInfo betterMatch = MethodBinder.MatchSignatureAndParameters(self.m.info, genericTp, sigTp);
						if (betterMatch != null) self.info = betterMatch;
					}
				}
			}

			// This supports calling a method 'unbound', passing the instance
			// as the first argument. Note that this is not supported if any
			// of the overloads are static since we can't know if the intent
			// was to call the static method or the unbound instance method.

			if ((self.target == IntPtr.Zero) && (!self.m.IsStatic()))
			{
				int len = Runtime.PyTuple_Size(args);
				if (len < 1)
				{
					Exceptions.SetError(Exceptions.TypeError, "not enough arguments");
					return IntPtr.Zero;
				}
				IntPtr uargs = Runtime.PyTuple_GetSlice(args, 1, len);
				IntPtr inst = Runtime.PyTuple_GetItem(args, 0);
				Runtime.Incref(inst);
				IntPtr r = self.m.Invoke(inst, uargs, kw, self.info);
				Runtime.Decref(inst);
				Runtime.Decref(uargs);
				return r;
			}

			return self.m.Invoke(self.target, args, kw, self.info);
        }


        //====================================================================
        // MethodBinding  __hash__ implementation.
        //====================================================================

        public static IntPtr tp_hash(IntPtr ob) {
            MethodBinding self = (MethodBinding)GetManagedObject(ob);
            long x = 0;
            long y = 0;

            if (self.target != IntPtr.Zero) {
                x = Runtime.PyObject_Hash(self.target).ToInt64();
                if (x == -1) {
                    return new IntPtr(-1);
                }
            }
 
            y = Runtime.PyObject_Hash(self.m.pyHandle).ToInt64();
            if (y == -1) {
                return new IntPtr(-1);
            }

            x ^= y;

            if (x == -1) {
                x = -1;
            }

            return new IntPtr(x);
        }

        //====================================================================
        // MethodBinding  __repr__ implementation.
        //====================================================================

        public static IntPtr tp_repr(IntPtr ob) {
            MethodBinding self = (MethodBinding)GetManagedObject(ob);
            string type = (self.target == IntPtr.Zero) ? "unbound" : "bound";
            string s = String.Format("", type, self.m.name);
            return Runtime.PyString_FromStringAndSize(s, s.Length);
        }

        //====================================================================
        // MethodBinding dealloc implementation.
        //====================================================================

        public static new void tp_dealloc(IntPtr ob) {
            MethodBinding self = (MethodBinding)GetManagedObject(ob);
            Runtime.Decref(self.target);
            ExtensionType.FinalizeObject(self);
        }

    }


}

Web Proxy Viewer  |  New URL  |  Original Page