Пример #1
0
        /// <summary>
        /// Return value: Borrowed reference.
        /// Get the handle of a Python type that reflects the given CLR type.
        /// The given ManagedType instance is a managed object that implements
        /// the appropriate semantics in Python for the reflected managed type.
        /// </summary>
        internal static IntPtr GetTypeHandle(ClassBase obj, Type type)
        {
            IntPtr handle;

            cache.TryGetValue(type, out handle);
            if (handle != IntPtr.Zero)
            {
                return(handle);
            }
            handle      = CreateType(obj, type);
            cache[type] = handle;
            _slotsImpls.Add(type, obj.GetType());
            return(handle);
        }
Пример #2
0
        internal static IntPtr CreateType(ClassBase impl, Type clrType)
        {
            // Cleanup the type name to get rid of funny nested type names.
            string name = $"clr.{clrType.FullName}";
            int    i    = name.LastIndexOf('+');

            if (i > -1)
            {
                name = name.Substring(i + 1);
            }
            i = name.LastIndexOf('.');
            if (i > -1)
            {
                name = name.Substring(i + 1);
            }

            IntPtr base_ = Runtime.PyBaseObjectType;

            if (clrType == typeof(Exception))
            {
                base_ = Exceptions.Exception;
            }
            else if (clrType.BaseType != null)
            {
                ClassBase bc = ClassManager.GetClass(clrType.BaseType);
                if (bc.ObjectReference != null)
                {
                    // there are cases when base class has not been fully initialized yet (nested types)
                    base_ = bc.pyHandle;
                }
            }

            IntPtr type = AllocateTypeObject(name, Runtime.PyCLRMetaType);

            int newFieldOffset = InheritOrAllocateStandardFields(type, base_);

            if (ManagedType.IsManagedType(new BorrowedReference(base_)))
            {
                int baseClrInstOffset = Marshal.ReadInt32(base_, ManagedType.Offsets.tp_clr_inst_offset);
                Marshal.WriteInt32(type, ManagedType.Offsets.tp_clr_inst_offset, baseClrInstOffset);
            }
            else
            {
                Marshal.WriteInt32(type, ManagedType.Offsets.tp_clr_inst_offset, newFieldOffset);
                newFieldOffset += IntPtr.Size;
            }

            int ob_size = newFieldOffset;

            Marshal.WriteIntPtr(type, TypeOffset.tp_basicsize, (IntPtr)ob_size);
            Marshal.WriteIntPtr(type, TypeOffset.tp_itemsize, IntPtr.Zero);

            // we want to do this after the slot stuff above in case the class itself implements a slot method
            SlotsHolder slotsHolder = CreateSolotsHolder(type);

            InitializeSlots(type, impl.GetType(), slotsHolder);

            if (Marshal.ReadIntPtr(type, TypeOffset.mp_length) == IntPtr.Zero &&
                mp_length_slot.CanAssign(clrType))
            {
                InitializeSlot(type, TypeOffset.mp_length, mp_length_slot.Method, slotsHolder);
            }

            if (!typeof(IEnumerable).IsAssignableFrom(clrType) &&
                !typeof(IEnumerator).IsAssignableFrom(clrType))
            {
                // The tp_iter slot should only be set for enumerable types.
                Marshal.WriteIntPtr(type, TypeOffset.tp_iter, IntPtr.Zero);
            }


            // Only set mp_subscript and mp_ass_subscript for types with indexers
            if (!(impl is ArrayObject))
            {
                if (impl.indexer == null || !impl.indexer.CanGet)
                {
                    Marshal.WriteIntPtr(type, TypeOffset.mp_subscript, IntPtr.Zero);
                }
                if (impl.indexer == null || !impl.indexer.CanSet)
                {
                    Marshal.WriteIntPtr(type, TypeOffset.mp_ass_subscript, IntPtr.Zero);
                }
            }

            if (base_ != IntPtr.Zero)
            {
                Marshal.WriteIntPtr(type, TypeOffset.tp_base, base_);
                Runtime.XIncref(base_);
            }

            const TypeFlags flags = TypeFlags.Default
                                    | TypeFlags.HasClrInstance
                                    | TypeFlags.HeapType
                                    | TypeFlags.BaseType
                                    | TypeFlags.HaveGC;

            Util.WriteCLong(type, TypeOffset.tp_flags, (int)flags);

            OperatorMethod.FixupSlots(type, clrType);
            // Leverage followup initialization from the Python runtime. Note
            // that the type of the new type must PyType_Type at the time we
            // call this, else PyType_Ready will skip some slot initialization.

            if (Runtime.PyType_Ready(type) != 0)
            {
                throw new PythonException();
            }

            var    dict = new BorrowedReference(Marshal.ReadIntPtr(type, TypeOffset.tp_dict));
            string mn   = clrType.Namespace ?? "";
            var    mod  = NewReference.DangerousFromPointer(Runtime.PyString_FromString(mn));

            Runtime.PyDict_SetItem(dict, PyIdentifier.__module__, mod);
            mod.Dispose();

            var typeRef = new BorrowedReference(type);

            // Hide the gchandle of the implementation in a magic type slot.
            GCHandle gc = impl.AllocGCHandle();

            ManagedType.InitGCHandle(typeRef, Runtime.CLRMetaType, gc);

            // Set the handle attributes on the implementing instance.
            impl.tpHandle = type;
            impl.pyHandle = type;

            //DebugUtil.DumpType(type);

            return(type);
        }