22using System ;
33using System . Collections ;
44using System . Collections . Generic ;
5+ using System . Diagnostics ;
56using System . Globalization ;
67using System . Reflection ;
78using System . Runtime . InteropServices ;
@@ -501,6 +502,44 @@ internal static bool ToManagedValue(IntPtr value, Type obType,
501502 return ToPrimitive ( value , obType , out result , setError ) ;
502503 }
503504
505+ /// <remarks>
506+ /// Unlike <see cref="ToManaged(BorrowedReference, Type, out object?, bool)"/>,
507+ /// this method does not have a <c>setError</c> parameter, because it should
508+ /// only be called after <see cref="ToManaged(BorrowedReference, Type, out object?, bool)"/>.
509+ /// </remarks>
510+ internal static bool ToManagedExplicit ( BorrowedReference value , Type obType ,
511+ out object ? result )
512+ {
513+ result = null ;
514+
515+ // this method would potentially clean any existing error resulting in information loss
516+ Debug . Assert ( Runtime . PyErr_Occurred ( ) == null ) ;
517+
518+ string ? converterName =
519+ IsInteger ( obType ) ? "__int__"
520+ : IsFloatingNumber ( obType ) ? "__float__"
521+ : null ;
522+
523+ if ( converterName is null ) return false ;
524+
525+ Debug . Assert ( obType . IsPrimitive ) ;
526+
527+ using var converter = Runtime . PyObject_GetAttrString ( value , converterName ) ;
528+ if ( converter . IsNull ( ) )
529+ {
530+ Exceptions . Clear ( ) ;
531+ return false ;
532+ }
533+
534+ using var explicitlyCoerced = Runtime . PyObject_CallObject ( converter , BorrowedReference . Null ) ;
535+ if ( explicitlyCoerced . IsNull ( ) )
536+ {
537+ Exceptions . Clear ( ) ;
538+ return false ;
539+ }
540+ return ToPrimitive ( explicitlyCoerced , obType , out result , false ) ;
541+ }
542+
504543 static object ? ToPyObjectSubclass ( ConstructorInfo ctor , PyObject instance , bool setError )
505544 {
506545 try
@@ -544,6 +583,8 @@ internal static int ToInt32(BorrowedReference value)
544583 return checked ( ( int ) num ) ;
545584 }
546585
586+ private static bool ToPrimitive ( BorrowedReference value , Type obType , out object ? result , bool setError )
587+ => ToPrimitive ( value . DangerousGetAddress ( ) , obType , out result , setError ) ;
547588 /// <summary>
548589 /// Convert a Python value to an instance of a primitive managed type.
549590 /// </summary>
@@ -590,7 +631,18 @@ private static bool ToPrimitive(IntPtr value, Type obType, out object? result, b
590631 }
591632
592633 case TypeCode . Boolean :
593- result = Runtime . PyObject_IsTrue ( value ) != 0 ;
634+ if ( value == Runtime . PyTrue )
635+ {
636+ result = true ;
637+ }
638+ else if ( value == Runtime . PyFalse )
639+ {
640+ result = false ;
641+ }
642+ else if ( setError )
643+ {
644+ goto type_error ;
645+ }
594646 return true ;
595647
596648 case TypeCode . Byte :
@@ -768,6 +820,10 @@ private static bool ToPrimitive(IntPtr value, Type obType, out object? result, b
768820
769821 case TypeCode . Single :
770822 {
823+ if ( ! Runtime . PyFloat_Check ( value ) && ! Runtime . PyInt_Check ( value ) )
824+ {
825+ goto type_error ;
826+ }
771827 double num = Runtime . PyFloat_AsDouble ( value ) ;
772828 if ( num == - 1.0 && Exceptions . ErrorOccurred ( ) )
773829 {
@@ -786,6 +842,10 @@ private static bool ToPrimitive(IntPtr value, Type obType, out object? result, b
786842
787843 case TypeCode . Double :
788844 {
845+ if ( ! Runtime . PyFloat_Check ( value ) && ! Runtime . PyInt_Check ( value ) )
846+ {
847+ goto type_error ;
848+ }
789849 double num = Runtime . PyFloat_AsDouble ( value ) ;
790850 if ( num == - 1.0 && Exceptions . ErrorOccurred ( ) )
791851 {
@@ -933,6 +993,13 @@ private static bool ToArray(IntPtr value, Type obType, out object? result, bool
933993 result = items ;
934994 return true ;
935995 }
996+
997+ internal static bool IsFloatingNumber ( Type type ) => type == typeof ( float ) || type == typeof ( double ) ;
998+ internal static bool IsInteger ( Type type )
999+ => type == typeof ( Byte ) || type == typeof ( SByte )
1000+ || type == typeof ( Int16 ) || type == typeof ( UInt16 )
1001+ || type == typeof ( Int32 ) || type == typeof ( UInt32 )
1002+ || type == typeof ( Int64 ) || type == typeof ( UInt64 ) ;
9361003 }
9371004
9381005 public static class ConverterExtension
0 commit comments