/// <summary> /// Convert a Python value to an instance of a primitive managed type. /// </summary> private static bool ToPrimitive(BorrowedReference value, Type obType, out object?result, bool setError) { result = null; if (obType.IsEnum) { if (setError) { Exceptions.SetError(Exceptions.TypeError, "since Python.NET 3.0 int can not be converted to Enum implicitly. Use Enum(int_value)"); } return(false); } TypeCode tc = Type.GetTypeCode(obType); switch (tc) { case TypeCode.String: string?st = Runtime.GetManagedString(value); if (st == null) { goto type_error; } result = st; return(true); case TypeCode.Int32: { // Python3 always use PyLong API nint num = Runtime.PyLong_AsSignedSize_t(value); if (num == -1 && Exceptions.ErrorOccurred()) { goto convert_error; } if (num > Int32.MaxValue || num < Int32.MinValue) { goto overflow; } result = (int)num; return(true); } case TypeCode.Boolean: if (value == Runtime.PyTrue) { result = true; return(true); } if (value == Runtime.PyFalse) { result = false; return(true); } if (setError) { goto type_error; } return(false); case TypeCode.Byte: { if (Runtime.PyObject_TypeCheck(value, Runtime.PyBytesType)) { if (Runtime.PyBytes_Size(value) == 1) { IntPtr bytePtr = Runtime.PyBytes_AsString(value); result = (byte)Marshal.ReadByte(bytePtr); return(true); } goto type_error; } nint num = Runtime.PyLong_AsSignedSize_t(value); if (num == -1 && Exceptions.ErrorOccurred()) { goto convert_error; } if (num > Byte.MaxValue || num < Byte.MinValue) { goto overflow; } result = (byte)num; return(true); } case TypeCode.SByte: { if (Runtime.PyObject_TypeCheck(value, Runtime.PyBytesType)) { if (Runtime.PyBytes_Size(value) == 1) { IntPtr bytePtr = Runtime.PyBytes_AsString(value); result = (sbyte)Marshal.ReadByte(bytePtr); return(true); } goto type_error; } nint num = Runtime.PyLong_AsSignedSize_t(value); if (num == -1 && Exceptions.ErrorOccurred()) { goto convert_error; } if (num > SByte.MaxValue || num < SByte.MinValue) { goto overflow; } result = (sbyte)num; return(true); } case TypeCode.Char: { if (Runtime.PyObject_TypeCheck(value, Runtime.PyBytesType)) { if (Runtime.PyBytes_Size(value) == 1) { IntPtr bytePtr = Runtime.PyBytes_AsString(value); result = (char)Marshal.ReadByte(bytePtr); return(true); } goto type_error; } else if (Runtime.PyObject_TypeCheck(value, Runtime.PyUnicodeType)) { if (Runtime.PyUnicode_GetLength(value) == 1) { IntPtr unicodePtr = Runtime.PyUnicode_AsUnicode(value); Char[] buff = new Char[1]; Marshal.Copy(unicodePtr, buff, 0, 1); result = buff[0]; return(true); } goto type_error; } nint num = Runtime.PyLong_AsSignedSize_t(value); if (num == -1 && Exceptions.ErrorOccurred()) { goto convert_error; } if (num > Char.MaxValue || num < Char.MinValue) { goto overflow; } result = (char)num; return(true); } case TypeCode.Int16: { nint num = Runtime.PyLong_AsSignedSize_t(value); if (num == -1 && Exceptions.ErrorOccurred()) { goto convert_error; } if (num > Int16.MaxValue || num < Int16.MinValue) { goto overflow; } result = (short)num; return(true); } case TypeCode.Int64: { if (Runtime.Is32Bit) { if (!Runtime.PyLong_Check(value)) { goto type_error; } long?num = Runtime.PyLong_AsLongLong(value); if (num is null) { goto convert_error; } result = num.Value; return(true); } else { nint num = Runtime.PyLong_AsSignedSize_t(value); if (num == -1 && Exceptions.ErrorOccurred()) { goto convert_error; } result = (long)num; return(true); } } case TypeCode.UInt16: { nint num = Runtime.PyLong_AsSignedSize_t(value); if (num == -1 && Exceptions.ErrorOccurred()) { goto convert_error; } if (num > UInt16.MaxValue || num < UInt16.MinValue) { goto overflow; } result = (ushort)num; return(true); } case TypeCode.UInt32: { nuint num = Runtime.PyLong_AsUnsignedSize_t(value); if (num == unchecked ((nuint)(-1)) && Exceptions.ErrorOccurred()) { goto convert_error; } if (num > UInt32.MaxValue) { goto overflow; } result = (uint)num; return(true); } case TypeCode.UInt64: { ulong?num = Runtime.PyLong_AsUnsignedLongLong(value); if (num is null) { goto convert_error; } result = num.Value; return(true); } case TypeCode.Single: { if (!Runtime.PyFloat_Check(value) && !Runtime.PyInt_Check(value)) { goto type_error; } double num = Runtime.PyFloat_AsDouble(value); if (num == -1.0 && Exceptions.ErrorOccurred()) { goto convert_error; } if (num > Single.MaxValue || num < Single.MinValue) { if (!double.IsInfinity(num)) { goto overflow; } } result = (float)num; return(true); } case TypeCode.Double: { if (!Runtime.PyFloat_Check(value) && !Runtime.PyInt_Check(value)) { goto type_error; } double num = Runtime.PyFloat_AsDouble(value); if (num == -1.0 && Exceptions.ErrorOccurred()) { goto convert_error; } result = num; return(true); } default: goto type_error; } convert_error: if (!setError) { Exceptions.Clear(); } return(false); type_error: if (setError) { string tpName = Runtime.PyObject_GetTypeName(value); Exceptions.SetError(Exceptions.TypeError, $"'{tpName}' value cannot be converted to {obType}"); } return(false); overflow: // C# level overflow error if (setError) { Exceptions.SetError(Exceptions.OverflowError, "value too large to convert"); } return(false); }