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);
}