using System;
using System.Diagnostics;
using System.Runtime.Serialization;
using Python.Runtime.Native;
namespace Python.Runtime
{
[Serializable]
public class PyType : PyObject
{
/// Creates heap type object from the .
public PyType(TypeSpec spec, PyTuple? bases = null) : base(FromSpec(spec, bases)) { }
/// Wraps an existing type object.
public PyType(PyObject o) : base(FromObject(o)) { }
internal PyType(PyType o)
: base(o is not null ? o.Reference : throw new ArgumentNullException(nameof(o)))
{
}
internal PyType(BorrowedReference reference, bool prevalidated = false) : base(reference)
{
if (prevalidated) return;
if (!Runtime.PyType_Check(this))
throw new ArgumentException("object is not a type");
}
internal PyType(in StolenReference reference, bool prevalidated = false) : base(reference)
{
if (prevalidated) return;
if (!Runtime.PyType_Check(this))
throw new ArgumentException("object is not a type");
}
protected PyType(SerializationInfo info, StreamingContext context) : base(info, context) { }
internal new static PyType? FromNullableReference(BorrowedReference reference)
=> reference == null
? null
: new PyType(new NewReference(reference).Steal());
internal static PyType FromReference(BorrowedReference reference)
=> FromNullableReference(reference) ?? throw new ArgumentNullException(nameof(reference));
public string Name
{
get
{
var namePtr = new StrPtr
{
RawPointer = Util.ReadIntPtr(this, TypeOffset.tp_name),
};
return namePtr.ToString(Encodings.UTF8)!;
}
}
/// Returns true when type is fully initialized
public bool IsReady => Flags.HasFlag(TypeFlags.Ready);
internal TypeFlags Flags
{
get => (TypeFlags)Util.ReadCLong(this, TypeOffset.tp_flags);
set => Util.WriteCLong(this, TypeOffset.tp_flags, (long)value);
}
internal PyDict Dict => new(Util.ReadRef(this, TypeOffset.tp_dict));
internal PyTuple MRO => new(GetMRO(this));
/// Checks if specified object is a Python type.
public static bool IsType(PyObject value)
{
if (value is null) throw new ArgumentNullException(nameof(value));
return Runtime.PyType_Check(value.obj);
}
/// Checks if specified object is a Python type.
internal static bool IsType(BorrowedReference value)
{
return Runtime.PyType_Check(value);
}
///
/// Gets , which represents the specified CLR type.
///
public static PyType Get(Type clrType)
{
if (clrType is null)
{
throw new ArgumentNullException(nameof(clrType));
}
return new PyType(ClassManager.GetClass(clrType));
}
internal BorrowedReference BaseReference
{
get => GetBase(Reference);
set => Runtime.ReplaceReference(this, TypeOffset.tp_base, new NewReference(value).Steal());
}
internal IntPtr GetSlot(TypeSlotID slot)
{
IntPtr result = Runtime.PyType_GetSlot(this.Reference, slot);
return Exceptions.ErrorCheckIfNull(result);
}
internal static TypeFlags GetFlags(BorrowedReference type)
{
Debug.Assert(TypeOffset.tp_flags > 0);
return (TypeFlags)Util.ReadCLong(type, TypeOffset.tp_flags);
}
internal static void SetFlags(BorrowedReference type, TypeFlags flags)
{
Debug.Assert(TypeOffset.tp_flags > 0);
Util.WriteCLong(type, TypeOffset.tp_flags, (long)flags);
}
internal static BorrowedReference GetBase(BorrowedReference type)
{
Debug.Assert(IsType(type));
return Util.ReadRef(type, TypeOffset.tp_base);
}
internal static BorrowedReference GetBases(BorrowedReference type)
{
Debug.Assert(IsType(type));
return Util.ReadRef(type, TypeOffset.tp_bases);
}
internal static BorrowedReference GetMRO(BorrowedReference type)
{
Debug.Assert(IsType(type));
return Util.ReadRef(type, TypeOffset.tp_mro);
}
private static BorrowedReference FromObject(PyObject o)
{
if (o is null) throw new ArgumentNullException(nameof(o));
if (!IsType(o)) throw new ArgumentException("object is not a type");
return o.Reference;
}
private static StolenReference FromSpec(TypeSpec spec, PyTuple? bases = null)
{
if (spec is null) throw new ArgumentNullException(nameof(spec));
if ((spec.Flags & TypeFlags.HeapType) == 0)
throw new NotSupportedException("Only heap types are supported");
using var nativeSpec = new NativeTypeSpec(spec);
var basesRef = bases is null ? default : bases.Reference;
var result = Runtime.PyType_FromSpecWithBases(in nativeSpec, basesRef);
// Runtime.PyErr_Print();
return result.StealOrThrow();
}
}
}