diff --git a/src/core/IronPython.Modules/ModuleOps.cs b/src/core/IronPython.Modules/ModuleOps.cs
index 27d912bdf..7050a46e8 100644
--- a/src/core/IronPython.Modules/ModuleOps.cs
+++ b/src/core/IronPython.Modules/ModuleOps.cs
@@ -21,7 +21,7 @@
namespace IronPython.Modules {
///
- /// Provides helper functions which need to be called from generated code to implement various
+ /// Provides helper functions which need to be called from generated code to implement various
/// portions of modules.
///
public static partial class ModuleOps {
@@ -110,7 +110,7 @@ public static CTypes.CData CheckSimpleCDataType(object o, object type) {
if (res == null && PythonOps.TryGetBoundAttr(o, "_as_parameter_", out object asParam)) {
res = asParam as CTypes._CFuncPtr;
}
-
+
if (res == null || res.NativeType != type) {
throw ArgumentError(type, ((PythonType)type).Name, o);
}
@@ -298,9 +298,6 @@ public static IntPtr GetPointer(object value) {
}
if (value is int iVal) {
- if(iVal > int.MaxValue) {
- iVal = -1;
- }
return new IntPtr(iVal);
}
@@ -357,13 +354,8 @@ public static IntPtr GetObject(object value) {
}
public static long GetSignedLongLong(object value, object type) {
- int? res = Converter.ImplicitConvertToInt32(value);
- if (res != null) {
- return res.Value;
- }
-
- if (value is BigInteger) {
- return (long)(BigInteger)value;
+ if (PythonOps.TryToInt(value, out BigInteger bi)) {
+ return unchecked((long)(ulong)(bi & ulong.MaxValue));
}
if (PythonOps.TryGetBoundAttr(value, "_as_parameter_", out object asParam)) {
@@ -373,14 +365,9 @@ public static long GetSignedLongLong(object value, object type) {
throw PythonOps.TypeErrorForTypeMismatch("signed long long ", value);
}
- public static long GetUnsignedLongLong(object value, object type) {
- int? res = Converter.ImplicitConvertToInt32(value);
- if (res != null && res.Value >= 0) {
- return res.Value;
- }
-
- if (value is BigInteger) {
- return (long)(ulong)(BigInteger)value;
+ public static ulong GetUnsignedLongLong(object value, object type) {
+ if (PythonOps.TryToInt(value, out BigInteger bi)) {
+ return (ulong)(bi & ulong.MaxValue);
}
if (PythonOps.TryGetBoundAttr(value, "_as_parameter_", out object asParam)) {
@@ -463,17 +450,8 @@ public static int GetSingleBits(object value) {
}
public static int GetSignedLong(object value, object type) {
- if (value is int) {
- return (int)value;
- }
-
- int? res = Converter.ImplicitConvertToInt32(value);
- if (res != null) {
- return res.Value;
- }
-
- if (value is BigInteger && ((BigInteger)value).AsUInt32(out uint unsigned)) {
- return (int)unsigned;
+ if (TryToIntStrict(value, out BigInteger bi)) {
+ return unchecked((int)(uint)(bi & uint.MaxValue));
}
if (PythonOps.TryGetBoundAttr(value, "_as_parameter_", out object asParam)) {
@@ -483,16 +461,9 @@ public static int GetSignedLong(object value, object type) {
throw PythonOps.TypeErrorForTypeMismatch("signed long", value);
}
- public static int GetUnsignedLong(object value, object type) {
- int? res = Converter.ImplicitConvertToInt32(value);
- if (res != null) {
- return res.Value;
- }
-
- if (value is BigInteger) {
- if (((BigInteger)value).AsUInt32(out uint ures)) {
- return (int)ures;
- }
+ public static uint GetUnsignedLong(object value, object type) {
+ if (PythonOps.TryToInt(value, out BigInteger bi)) {
+ return (uint)(bi & uint.MaxValue);
}
if (PythonOps.TryGetBoundAttr(value, "_as_parameter_", out object asParam)) {
@@ -502,24 +473,23 @@ public static int GetUnsignedLong(object value, object type) {
throw PythonOps.TypeErrorForTypeMismatch("unsigned long", value);
}
- public static int GetUnsignedInt(object value, object type) {
- int? res = Converter.ImplicitConvertToInt32(value);
- if (res != null && res.Value >= 0) {
- return res.Value;
+ public static uint GetUnsignedInt(object value, object type) {
+ if (TryToIntStrict(value, out BigInteger bi)) {
+ return (uint)(bi & uint.MaxValue);
}
if (PythonOps.TryGetBoundAttr(value, "_as_parameter_", out object asParam)) {
- return GetUnsignedInt(type, asParam);
+ return GetUnsignedInt(asParam, type);
}
throw PythonOps.TypeErrorForTypeMismatch("unsigned int", value);
}
public static int GetSignedInt(object value, object type) {
- int? res = Converter.ImplicitConvertToInt32(value);
- if (res != null) {
- return res.Value;
+ if (TryToIntStrict(value, out BigInteger bi)) {
+ return unchecked((int)(bi & uint.MaxValue));
}
+
if (PythonOps.TryGetBoundAttr(value, "_as_parameter_", out object asParam)) {
return GetSignedInt(asParam, type);
}
@@ -528,13 +498,10 @@ public static int GetSignedInt(object value, object type) {
}
public static ushort GetUnsignedShort(object value, object type) {
- int? res = Converter.ImplicitConvertToInt32(value);
- if (res != null) {
- int iVal = res.Value;
- if (iVal >= ushort.MinValue && iVal <= ushort.MaxValue) {
- return (ushort)iVal;
- }
+ if (PythonOps.TryToInt(value, out BigInteger bi)) {
+ return (ushort)(bi & ushort.MaxValue);
}
+
if (PythonOps.TryGetBoundAttr(value, "_as_parameter_", out object asParam)) {
return GetUnsignedShort(asParam, type);
}
@@ -543,12 +510,8 @@ public static ushort GetUnsignedShort(object value, object type) {
}
public static short GetSignedShort(object value, object type) {
- int? res = Converter.ImplicitConvertToInt32(value);
- if (res != null) {
- int iVal = res.Value;
- return (short)iVal;
- } else if (value is BigInteger bigInt) {
- return (short)(int)(bigInt & 0xffff);
+ if (PythonOps.TryToInt(value, out BigInteger bi)) {
+ return unchecked((short)(ushort)(bi & ushort.MaxValue));
}
if (PythonOps.TryGetBoundAttr(value, "_as_parameter_", out object asParam)) {
@@ -563,9 +526,8 @@ public static int GetVariantBool(object value, object type) {
}
public static byte GetUnsignedByte(object value, object type) {
- int? res = Converter.ImplicitConvertToInt32(value);
- if (res != null) {
- return (byte)res.Value;
+ if (PythonOps.TryToInt(value, out BigInteger bi)) {
+ return (byte)(bi & byte.MaxValue);
}
if (PythonOps.TryGetBoundAttr(value, "_as_parameter_", out object asParam)) {
@@ -576,12 +538,8 @@ public static byte GetUnsignedByte(object value, object type) {
}
public static sbyte GetSignedByte(object value, object type) {
- int? res = Converter.ImplicitConvertToInt32(value);
- if (res != null) {
- int iVal = res.Value;
- if (iVal >= sbyte.MinValue && iVal <= sbyte.MaxValue) {
- return (sbyte)iVal;
- }
+ if (PythonOps.TryToInt(value, out BigInteger bi)) {
+ return unchecked((sbyte)(byte)(bi & byte.MaxValue));
}
if (PythonOps.TryGetBoundAttr(value, "_as_parameter_", out object asParam)) {
@@ -639,7 +597,7 @@ public static char GetWChar(object value, object type) {
return GetWChar(asParam, type);
}
- throw PythonOps.TypeError("unicode string expected instead of {0} instance", PythonOps.GetPythonTypeName(value));
+ throw PythonOps.TypeErrorForBadInstance("unicode string expected instead of {0} instance", value);
}
public static object IntPtrToObject(IntPtr address) {
@@ -650,6 +608,22 @@ public static object IntPtrToObject(IntPtr address) {
return res;
}
+ internal static bool TryToIntStrict(object value, out BigInteger bi) {
+ // When IronPython upgrades to Python 3.10, this method becomes obsolete
+ // and can be replaced with PythonOps.TryToIndex(value, out bi)
+ if (IsFloatingPoint(value)) {
+ throw PythonOps.TypeErrorForBadInstance("int expected instead of {0}", value);
+ }
+
+ return PythonOps.TryToInt(value, out bi);
+ }
+
+ internal static bool IsFloatingPoint(object value)
+ => value is double or float
+#if NETCOREAPP
+ or Half
+#endif
+ ;
}
}
#endif
diff --git a/src/core/IronPython.Modules/_ctypes/SimpleCData.cs b/src/core/IronPython.Modules/_ctypes/SimpleCData.cs
index 9bb1cb126..1babc2e66 100644
--- a/src/core/IronPython.Modules/_ctypes/SimpleCData.cs
+++ b/src/core/IronPython.Modules/_ctypes/SimpleCData.cs
@@ -10,6 +10,7 @@
using System.Runtime.CompilerServices;
using Microsoft.Scripting.Runtime;
+using Microsoft.Scripting.Utils;
using IronPython.Runtime;
using IronPython.Runtime.Operations;
@@ -41,12 +42,8 @@ public void __init__(CodeContext/*!*/ context, object value) {
{
if (value is IList t && t.Count == 1) {
value = Bytes.FromByte(t[0]);
- } else if (value is int i) {
- try {
- value = Bytes.FromByte(checked((byte)i));
- } catch (OverflowException) {
- throw PythonOps.TypeError("one character bytes, bytearray or integer expected");
- }
+ } else if (Converter.TryConvertToByte(value, out byte b) && !ModuleOps.IsFloatingPoint(value)) {
+ value = Bytes.FromByte(b);
} else {
throw PythonOps.TypeError("one character bytes, bytearray or integer expected");
}
@@ -60,25 +57,20 @@ public void __init__(CodeContext/*!*/ context, object value) {
}
}
break;
+ case SimpleTypeKind.SignedByte:
case SimpleTypeKind.SignedInt:
case SimpleTypeKind.SignedLong:
case SimpleTypeKind.SignedLongLong:
case SimpleTypeKind.SignedShort:
+ case SimpleTypeKind.UnsignedByte:
case SimpleTypeKind.UnsignedInt:
case SimpleTypeKind.UnsignedLong:
case SimpleTypeKind.UnsignedLongLong:
case SimpleTypeKind.UnsignedShort: {
- object __int__ = null;
- if (value is float || value is double) {
- throw PythonOps.TypeError("int expected instead of float");
- }
-
- if (!(value is int || value is BigInteger || PythonOps.TryGetBoundAttr(value, "__int__", out __int__))) {
- throw PythonOps.TypeError("an integer is required");
- }
-
- if (__int__ != null) {
- value = PythonOps.CallWithContext(context, __int__);
+ if (ModuleOps.TryToIntStrict(value, out BigInteger bi)) {
+ value = bi;
+ } else {
+ throw PythonOps.TypeErrorForBadInstance("an integer is required (got type {0})", value);
}
}
break;
@@ -92,7 +84,7 @@ public void __init__(CodeContext/*!*/ context, object value) {
if (value is BigInteger x) {
if (x > (BigInteger)double.MaxValue) {
- throw PythonOps.OverflowError("long int too large to convert to float");
+ throw PythonOps.OverflowError("Python int too large to convert to float");
}
}
diff --git a/src/core/IronPython.Modules/_ctypes/SimpleType.cs b/src/core/IronPython.Modules/_ctypes/SimpleType.cs
index 8f4c4a74f..2af7309c2 100644
--- a/src/core/IronPython.Modules/_ctypes/SimpleType.cs
+++ b/src/core/IronPython.Modules/_ctypes/SimpleType.cs
@@ -251,19 +251,19 @@ object INativeType.SetValue(MemoryHolder/*!*/ owner, int offset, object value) {
switch (_type) {
case SimpleTypeKind.Boolean: owner.WriteByte(offset, ModuleOps.GetBoolean(value, this)); break;
case SimpleTypeKind.Char: owner.WriteByte(offset, ModuleOps.GetChar(value, this)); break;
- case SimpleTypeKind.SignedByte: owner.WriteByte(offset, (byte)ModuleOps.GetSignedByte(value, this)); break;
+ case SimpleTypeKind.SignedByte: owner.WriteByte(offset, unchecked((byte)ModuleOps.GetSignedByte(value, this))); break;
case SimpleTypeKind.UnsignedByte: owner.WriteByte(offset, ModuleOps.GetUnsignedByte(value, this)); break;
- case SimpleTypeKind.WChar: owner.WriteInt16(offset, (short)ModuleOps.GetWChar(value, this)); break;
- case SimpleTypeKind.SignedShort: owner.WriteInt16(offset, ModuleOps.GetSignedShort(value, this), _swap); break;
- case SimpleTypeKind.UnsignedShort: owner.WriteInt16(offset, (short)ModuleOps.GetUnsignedShort(value, this), _swap); break;
- case SimpleTypeKind.VariantBool: owner.WriteInt16(offset, (short)ModuleOps.GetVariantBool(value, this), _swap); break;
+ case SimpleTypeKind.WChar: owner.WriteInt16(offset, unchecked((short)ModuleOps.GetWChar(value, this))); break;
+ case SimpleTypeKind.SignedShort: owner.WriteInt16(offset, ModuleOps.GetSignedShort(value, this), _swap); break;
+ case SimpleTypeKind.UnsignedShort: owner.WriteInt16(offset, unchecked((short)ModuleOps.GetUnsignedShort(value, this)), _swap); break;
+ case SimpleTypeKind.VariantBool: owner.WriteInt16(offset, unchecked((short)ModuleOps.GetVariantBool(value, this)), _swap); break;
case SimpleTypeKind.SignedInt: owner.WriteInt32(offset, ModuleOps.GetSignedInt(value, this), _swap); break;
- case SimpleTypeKind.UnsignedInt: owner.WriteInt32(offset, ModuleOps.GetUnsignedInt(value, this), _swap); break;
- case SimpleTypeKind.UnsignedLong: owner.WriteInt32(offset, ModuleOps.GetUnsignedLong(value, this), _swap); break;
+ case SimpleTypeKind.UnsignedInt: owner.WriteInt32(offset, unchecked((int)ModuleOps.GetUnsignedInt(value, this)), _swap); break;
+ case SimpleTypeKind.UnsignedLong: owner.WriteInt32(offset, unchecked((int)ModuleOps.GetUnsignedLong(value, this)), _swap); break;
case SimpleTypeKind.SignedLong: owner.WriteInt32(offset, ModuleOps.GetSignedLong(value, this), _swap); break;
case SimpleTypeKind.Single: owner.WriteInt32(offset, ModuleOps.GetSingleBits(value), _swap); break;
case SimpleTypeKind.Double: owner.WriteInt64(offset, ModuleOps.GetDoubleBits(value), _swap); break;
- case SimpleTypeKind.UnsignedLongLong: owner.WriteInt64(offset, ModuleOps.GetUnsignedLongLong(value, this), _swap); break;
+ case SimpleTypeKind.UnsignedLongLong: owner.WriteInt64(offset, unchecked((long)ModuleOps.GetUnsignedLongLong(value, this)), _swap); break;
case SimpleTypeKind.SignedLongLong: owner.WriteInt64(offset, ModuleOps.GetSignedLongLong(value, this), _swap); break;
case SimpleTypeKind.Object: owner.WriteIntPtr(offset, ModuleOps.GetObject(value)); break;
case SimpleTypeKind.Pointer: owner.WriteIntPtr(offset, ModuleOps.GetPointer(value)); break;
@@ -626,23 +626,23 @@ void INativeType.EmitReverseMarshalling(ILGenerator method, LocalOrArg value, Li
break;
case SimpleTypeKind.UnsignedInt:
case SimpleTypeKind.UnsignedLong:
- EmitInt32ToObject(method, value);
+ EmitUIntToObject(method, value);
break;
case SimpleTypeKind.UnsignedLongLong:
case SimpleTypeKind.SignedLongLong:
- EmitInt64ToObject(method, value);
+ EmitXInt64ToObject(method, value);
break;
case SimpleTypeKind.Object:
method.Emit(OpCodes.Call, typeof(ModuleOps).GetMethod(nameof(ModuleOps.IntPtrToObject)));
break;
case SimpleTypeKind.WCharPointer:
- method.Emit(OpCodes.Call, typeof(Marshal).GetMethod("PtrToStringUni", new[] { typeof(IntPtr) }));
+ method.Emit(OpCodes.Call, typeof(Marshal).GetMethod("PtrToStringUni", [typeof(IntPtr)]));
break;
case SimpleTypeKind.CharPointer:
method.Emit(OpCodes.Call, typeof(ModuleOps).GetMethod(nameof(ModuleOps.IntPtrToBytes)));
break;
case SimpleTypeKind.BStr:
- method.Emit(OpCodes.Call, typeof(Marshal).GetMethod("PtrToStringBSTR", new[] { typeof(IntPtr) }));
+ method.Emit(OpCodes.Call, typeof(Marshal).GetMethod("PtrToStringBSTR", [typeof(IntPtr)]));
break;
case SimpleTypeKind.Char:
method.Emit(OpCodes.Call, typeof(ModuleOps).GetMethod(nameof(ModuleOps.CharToBytes)));
@@ -669,12 +669,13 @@ void INativeType.EmitReverseMarshalling(ILGenerator method, LocalOrArg value, Li
method.MarkLabel(notNull);
method.Emit(OpCodes.Ldloc, tmpLocal);
- EmitInt32ToObject(method, new Local(tmpLocal));
+ EmitUIntToObject(method, new Local(tmpLocal));
} else {
LocalBuilder tmpLocal = method.DeclareLocal(typeof(long));
method.Emit(OpCodes.Conv_I8);
method.Emit(OpCodes.Stloc, tmpLocal);
method.Emit(OpCodes.Ldloc, tmpLocal);
+ method.Emit(OpCodes.Conv_U8);
method.Emit(OpCodes.Ldc_I4_0);
method.Emit(OpCodes.Conv_U8);
@@ -684,7 +685,7 @@ void INativeType.EmitReverseMarshalling(ILGenerator method, LocalOrArg value, Li
method.MarkLabel(notNull);
method.Emit(OpCodes.Ldloc, tmpLocal);
- EmitInt64ToObject(method, new Local(tmpLocal));
+ EmitXInt64ToObject(method, new Local(tmpLocal));
}
method.MarkLabel(done);
@@ -709,10 +710,13 @@ void INativeType.EmitReverseMarshalling(ILGenerator method, LocalOrArg value, Li
}
}
- private static void EmitInt64ToObject(ILGenerator method, LocalOrArg value) {
+ private static void EmitXInt64ToObject(ILGenerator method, LocalOrArg value) {
Label done;
Label bigInt = method.DefineLabel();
done = method.DefineLabel();
+ if (value.Type == typeof(ulong)) {
+ method.Emit(OpCodes.Conv_I8);
+ }
method.Emit(OpCodes.Ldc_I4, Int32.MaxValue);
method.Emit(OpCodes.Conv_I8);
method.Emit(OpCodes.Bgt, bigInt);
@@ -729,13 +733,13 @@ private static void EmitInt64ToObject(ILGenerator method, LocalOrArg value) {
method.MarkLabel(bigInt);
value.Emit(method);
- method.Emit(OpCodes.Call, typeof(BigInteger).GetMethod("op_Implicit", new[] { value.Type }));
+ method.Emit(OpCodes.Call, typeof(BigInteger).GetMethod("op_Implicit", [value.Type]));
method.Emit(OpCodes.Box, typeof(BigInteger));
method.MarkLabel(done);
}
- private static void EmitInt32ToObject(ILGenerator method, LocalOrArg value) {
+ private static void EmitUIntToObject(ILGenerator method, LocalOrArg value) {
Label intVal, done;
intVal = method.DefineLabel();
done = method.DefineLabel();
@@ -745,7 +749,7 @@ private static void EmitInt32ToObject(ILGenerator method, LocalOrArg value) {
method.Emit(OpCodes.Ble, intVal);
value.Emit(method);
- method.Emit(OpCodes.Call, typeof(BigInteger).GetMethod("op_Implicit", new[] { value.Type }));
+ method.Emit(OpCodes.Call, typeof(BigInteger).GetMethod("op_Implicit", [value.Type]));
method.Emit(OpCodes.Box, typeof(BigInteger));
method.Emit(OpCodes.Br, done);
diff --git a/src/core/IronPython.Modules/_opcode.cs b/src/core/IronPython.Modules/_opcode.cs
index b90dcddd1..e5e948a46 100644
--- a/src/core/IronPython.Modules/_opcode.cs
+++ b/src/core/IronPython.Modules/_opcode.cs
@@ -4,6 +4,8 @@
#nullable enable
+using System.Numerics;
+
using IronPython.Runtime;
using IronPython.Runtime.Operations;
@@ -155,10 +157,10 @@ public static int stack_effect(CodeContext context, int opcode, object? oparg =
throw PythonOps.ValueError("stack_effect: opcode requires oparg but oparg was not specified");
}
- if (!Converter.TryConvertToIndex(oparg, out ioparg)) { // supported since CPython 3.8
- ioparg = Converter.ImplicitConvertToInt32(oparg) ?? // warning since CPython 3.8, unsupported in 3.10
- throw PythonOps.TypeError($"an integer is required (got type {PythonOps.GetPythonTypeName(oparg)})");
+ if (!PythonOps.TryToInt(oparg, out BigInteger bioparg)) {
+ throw PythonOps.TypeError($"an integer is required (got type {PythonOps.GetPythonTypeName(oparg)})");
}
+ ioparg = (int)bioparg;
} else if (oparg != null) {
throw PythonOps.ValueError("stack_effect: opcode does not permit oparg but oparg was specified");
}
diff --git a/src/core/IronPython/Runtime/Operations/PythonOps.cs b/src/core/IronPython/Runtime/Operations/PythonOps.cs
index a4ac3df39..0efee5179 100644
--- a/src/core/IronPython/Runtime/Operations/PythonOps.cs
+++ b/src/core/IronPython/Runtime/Operations/PythonOps.cs
@@ -877,6 +877,26 @@ internal static bool TryToIndex(object? o, out BigInteger index) {
return false;
}
+ // This method is like `TryToIndex` but it additionally supports objects with `__int__`,
+ // which is expected for Python 3.7- and is supported until Python 3.10.
+ internal static bool TryToInt(object? o, out BigInteger res) {
+ if (TryToIndex(o, out res)) {
+ // supported since Python 3.8
+ return true;
+ }
+ if (PythonTypeOps.TryInvokeUnaryOperator(DefaultContext.Default, o, "__int__", out object objres)) {
+ // warning since Python 3.8, unsupported in 3.10
+ res = objres switch {
+ int i => i,
+ BigInteger bi => bi,
+ Extensible ebi => ebi.Value,
+ _ => throw TypeError("__int__ returned non-int (type {0})", PythonOps.GetPythonTypeName(objres))
+ };
+ return true;
+ }
+ return false;
+ }
+
private static bool IndexObjectToInt(object o, out int res, out BigInteger longRes) {
switch (o) {
case int i:
diff --git a/tests/suite/modules/type_related/test_ctypes.py b/tests/suite/modules/type_related/test_ctypes.py
index f4c1fdf3e..baa14825e 100644
--- a/tests/suite/modules/type_related/test_ctypes.py
+++ b/tests/suite/modules/type_related/test_ctypes.py
@@ -11,8 +11,31 @@
import sys
import gc
import unittest
+from decimal import Decimal
+
+from iptest import IronPythonTestCase, is_posix, is_cli, is_mono, is_netcoreapp, big, myint, run_test
+
+class MyInt:
+ def __init__(self, value):
+ self.value = value
+ def __int__(self):
+ return self.value
+
+class MyIndex:
+ def __init__(self, value):
+ self.value = value
+ def __index__(self):
+ return self.value
+
+class MyIntIndex:
+ def __init__(self, intValue, indexValue):
+ self.intValue = intValue
+ self.indexValue = indexValue
+ def __int__(self):
+ return self.intValue
+ def __index__(self):
+ return self.indexValue
-from iptest import IronPythonTestCase, is_posix, is_cli, is_mono, big, myint, run_test
class CTypesTest(IronPythonTestCase):
export_error_msg = "Existing exports of data: object cannot be re-sized" if is_cli else "cannot resize an array that is exporting buffers"
@@ -237,4 +260,164 @@ def test_loadlibrary_error(self):
self.assertIsNone(cm.exception.filename)
self.assertIsNone(cm.exception.filename2)
+
+ def test_conversions_c_int(self):
+ # normal case
+ c_int_value = c_int(42)
+ self.assertEqual(c_int_value.value, 42)
+
+ # bool case
+ c_int_value = c_int(True)
+ self.assertEqual(c_int_value.value, 1)
+
+ # BigInteger case
+ c_int_value = c_int(big(42))
+ self.assertEqual(c_int_value.value, 42)
+
+ if is_cli or sys.version_info < (3, 10):
+ # __int__ supported
+ c_int_value = c_int(MyInt(42))
+ self.assertEqual(c_int_value.value, 42)
+ c_int_value.value = MyInt(24)
+ self.assertEqual(c_int_value.value, 24)
+ else:
+ # __int__ not supported
+ self.assertRaises(TypeError, c_int, MyInt(42))
+ with self.assertRaises(TypeError):
+ c_int_value.value = MyInt(42)
+
+ if is_cli or sys.version_info >= (3, 8):
+ # __index__ supported
+ c_int_value = c_int(MyIndex(42))
+ self.assertEqual(c_int_value.value, 42)
+ c_int_value.value = MyIndex(24)
+ self.assertEqual(c_int_value.value, 24)
+
+ # __index__ takes priority over __int__
+ c_int_value = c_int(MyIntIndex(44, 42))
+ self.assertEqual(c_int_value.value, 42)
+ c_int_value.value = MyIntIndex(22, 24)
+ self.assertEqual(c_int_value.value, 24)
+ else:
+ # __index__ not supported
+ self.assertRaises(TypeError, c_int, MyIndex(42))
+ with self.assertRaises(TypeError):
+ c_int_value.value = MyIndex(42)
+
+ # str not supported
+ self.assertRaises(TypeError, c_int, "abc")
+ with self.assertRaises(TypeError):
+ c_int_value.value = "abc"
+
+ # float not supported
+ self.assertRaises(TypeError, c_int, 42.6)
+ with self.assertRaises(TypeError):
+ c_int_value.value = 42.6
+
+ # System.Single not supported
+ if is_cli:
+ import System
+ self.assertRaises(TypeError, c_int, System.Single(42.6))
+ with self.assertRaises(TypeError):
+ c_int_value.value = System.Single(42.6)
+
+ # System.Half not supported
+ if is_netcoreapp:
+ import System, clr
+ half = clr.Convert(42.6, System.Half)
+ self.assertRaises(TypeError, c_int, half)
+ with self.assertRaises(TypeError):
+ c_int_value.value = System.Half(42.6)
+
+ # Decimal is supported as long as __int__ is supported
+ if is_cli or sys.version_info < (3, 10):
+ c_int_value = c_int(Decimal(42.6))
+ else:
+ self.assertRaises(TypeError, c_int, Decimal(42.6))
+
+
+ def test_conversions_c_char(self):
+ # normal case (c_char is unsigned)
+ c_char_value = c_char(42)
+ self.assertEqual(c_char_value.value, b"*")
+
+ c_char_value = c_char(b"*")
+ self.assertEqual(c_char_value.value, b"*")
+
+ # bool case
+ c_cbyte_value = c_char(True)
+ self.assertEqual(c_cbyte_value.value, b"\x01")
+
+ # BigInteger case
+ c_cbyte_value = c_char(big(42))
+ self.assertEqual(c_cbyte_value.value, b"*")
+
+ # out of range int not supported
+ self.assertRaises(TypeError, c_char, 256)
+ self.assertRaises(TypeError, c_char, -1)
+ with self.assertRaises(TypeError):
+ c_char_value.value = 256
+ with self.assertRaises(TypeError):
+ c_char_value.value = -1
+
+ # longer bytes not supported
+ self.assertRaises(TypeError, c_char, b"abc")
+ with self.assertRaises(TypeError):
+ c_char_value.value = b"abc"
+
+ # __int__ not supported
+ self.assertRaises(TypeError, c_char, MyInt(42))
+ with self.assertRaises(TypeError):
+ c_char_value.value = MyInt(42)
+
+ # __index__ not supported
+ self.assertRaises(TypeError, c_char, MyIndex(42))
+ with self.assertRaises(TypeError):
+ c_char_value.value = MyIndex(42)
+
+ # str not supported
+ self.assertRaises(TypeError, c_char, "a")
+ with self.assertRaises(TypeError):
+ c_char_value.value = "a"
+
+ # float not supported
+ self.assertRaises(TypeError, c_char, 42.6)
+ with self.assertRaises(TypeError):
+ c_char_value.value = 42.6
+
+
+ def test_conversions_overflow(self):
+ # Overflow is clipped to lowest bits
+ c_int_value = c_int((42 << 60) + 24)
+ self.assertEqual(c_int_value.value, 24)
+ c_int_value.value = (42 << 60) + 12
+ self.assertEqual(c_int_value.value, 12)
+
+ c_int_value = c_int((-42 << 60) - 24)
+ self.assertEqual(c_int_value.value, -24)
+
+ c_longlong_value = c_longlong((42 << 80) + 24)
+ self.assertEqual(c_longlong_value.value, 24)
+ c_longlong_value.value = (42 << 80) + 12
+ self.assertEqual(c_longlong_value.value, 12)
+
+ c_short_value = c_short((42 << 20) + 24)
+ self.assertEqual(c_short_value.value, 24)
+ c_short_value.value = (42 << 20) + 12
+ self.assertEqual(c_short_value.value, 12)
+ c_short_value.value = 32768
+ self.assertEqual(c_short_value.value, -32768)
+ c_short_value.value = 32769
+ self.assertEqual(c_short_value.value, -32767)
+
+ c_byte_value = c_byte((42 << 10) + 4)
+ self.assertEqual(c_byte_value.value, 4)
+ c_byte_value.value = (42 << 10) + 2
+ self.assertEqual(c_byte_value.value, 2)
+ c_byte_value.value = 128
+ self.assertEqual(c_byte_value.value, -128)
+ c_byte_value.value = 129
+ self.assertEqual(c_byte_value.value, -127)
+
+
run_test(__name__)