Beispiel #1
0
        internal static bool ToManagedValue(IntPtr value, Type obType,
                                            out object result, bool setError, out bool usedImplicit)
        {
            usedImplicit = false;
            if (obType == typeof(PyObject))
            {
                Runtime.XIncref(value); // PyObject() assumes ownership
                result = new PyObject(value);
                return(true);
            }

            if (obType.IsGenericType && Runtime.PyObject_TYPE(value) == Runtime.PyListType)
            {
                var typeDefinition = obType.GetGenericTypeDefinition();
                if (typeDefinition == typeof(List <>))
                {
                    return(ToList(value, obType, out result, setError));
                }
            }

            // Common case: if the Python value is a wrapped managed object
            // instance, just return the wrapped object.
            ManagedType mt = ManagedType.GetManagedObject(value);

            result = null;

            if (mt != null)
            {
                if (mt is CLRObject co)
                {
                    object tmp = co.inst;
                    if (obType.IsInstanceOfType(tmp))
                    {
                        result = tmp;
                        return(true);
                    }
                    else
                    {
                        var type = tmp.GetType();
                        // check implicit conversions that receive tmp type and return obType
                        var conversionMethod = type.GetMethod("op_Implicit", new[] { type });
                        if (conversionMethod != null && conversionMethod.ReturnType == obType)
                        {
                            result       = conversionMethod.Invoke(null, new[] { tmp });
                            usedImplicit = true;
                            return(true);
                        }
                    }
                    if (setError)
                    {
                        string typeString = tmp is null ? "null" : tmp.GetType().ToString();
                        Exceptions.SetError(Exceptions.TypeError, $"{typeString} value cannot be converted to {obType}");
                    }
                    return(false);
                }
                if (mt is ClassBase cb)
                {
                    if (!cb.type.Valid)
                    {
                        Exceptions.SetError(Exceptions.TypeError, cb.type.DeletedMessage);
                        return(false);
                    }
                    result = cb.type.Value;
                    return(true);
                }
                // shouldn't happen
                return(false);
            }

            if (value == Runtime.PyNone && !obType.IsValueType)
            {
                result = null;
                return(true);
            }

            if (obType.IsGenericType && obType.GetGenericTypeDefinition() == typeof(Nullable <>))
            {
                if (value == Runtime.PyNone)
                {
                    result = null;
                    return(true);
                }
                // Set type to underlying type
                obType = obType.GetGenericArguments()[0];
            }

            if (obType.ContainsGenericParameters)
            {
                if (setError)
                {
                    Exceptions.SetError(Exceptions.TypeError, $"Cannot create an instance of the open generic type {obType}");
                }
                return(false);
            }

            if (obType.IsArray)
            {
                return(ToArray(value, obType, out result, setError));
            }

            if (obType.IsEnum)
            {
                return(ToEnum(value, obType, out result, setError));
            }

            // Conversion to 'Object' is done based on some reasonable default
            // conversions (Python string -> managed string, Python int -> Int32 etc.).
            if (obType == objectType)
            {
                if (Runtime.IsStringType(value))
                {
                    return(ToPrimitive(value, stringType, out result, setError));
                }

                if (Runtime.PyBool_Check(value))
                {
                    return(ToPrimitive(value, boolType, out result, setError));
                }

                if (Runtime.PyInt_Check(value))
                {
                    return(ToPrimitive(value, int32Type, out result, setError));
                }

                if (Runtime.PyLong_Check(value))
                {
                    return(ToPrimitive(value, int64Type, out result, setError));
                }

                if (Runtime.PyFloat_Check(value))
                {
                    return(ToPrimitive(value, doubleType, out result, setError));
                }

                // give custom codecs a chance to take over conversion of sequences
                IntPtr pyType = Runtime.PyObject_TYPE(value);
                if (PyObjectConversions.TryDecode(value, pyType, obType, out result))
                {
                    return(true);
                }

                if (Runtime.PySequence_Check(value))
                {
                    return(ToArray(value, typeof(object[]), out result, setError));
                }

                Runtime.XIncref(value); // PyObject() assumes ownership
                result = new PyObject(value);
                return(true);
            }

            // Conversion to 'Type' is done using the same mappings as above for objects.
            if (obType == typeType)
            {
                if (value == Runtime.PyStringType)
                {
                    result = stringType;
                    return(true);
                }

                if (value == Runtime.PyBoolType)
                {
                    result = boolType;
                    return(true);
                }

                if (value == Runtime.PyIntType)
                {
                    result = int32Type;
                    return(true);
                }

                if (value == Runtime.PyLongType)
                {
                    result = int64Type;
                    return(true);
                }

                if (value == Runtime.PyFloatType)
                {
                    result = doubleType;
                    return(true);
                }

                if (value == Runtime.PyListType || value == Runtime.PyTupleType)
                {
                    result = typeof(object[]);
                    return(true);
                }

                if (setError)
                {
                    Exceptions.SetError(Exceptions.TypeError, "value cannot be converted to Type");
                }

                return(false);
            }

            var underlyingType = Nullable.GetUnderlyingType(obType);

            if (underlyingType != null)
            {
                return(ToManagedValue(value, underlyingType, out result, setError, out usedImplicit));
            }

            TypeCode typeCode = Type.GetTypeCode(obType);

            if (typeCode == TypeCode.Object)
            {
                IntPtr pyType = Runtime.PyObject_TYPE(value);
                if (PyObjectConversions.TryDecode(value, pyType, obType, out result))
                {
                    return(true);
                }
            }

            var opImplicit = obType.GetMethod("op_Implicit", new[] { obType });

            if (opImplicit != null)
            {
                if (ToManagedValue(value, opImplicit.ReturnType, out result, setError, out usedImplicit))
                {
                    opImplicit = obType.GetMethod("op_Implicit", new[] { result.GetType() });
                    if (opImplicit != null)
                    {
                        result = opImplicit.Invoke(null, new[] { result });
                    }
                    return(opImplicit != null);
                }
            }

            return(ToPrimitive(value, obType, out result, setError));
        }
Beispiel #2
0
        internal static bool ToManagedValue(IntPtr value, Type obType,
                                            out object result, bool setError)
        {
            if (obType == typeof(PyObject))
            {
                Runtime.XIncref(value); // PyObject() assumes ownership
                result = new PyObject(value);
                return(true);
            }

            // Common case: if the Python value is a wrapped managed object
            // instance, just return the wrapped object.
            ManagedType mt = ManagedType.GetManagedObject(value);

            result = null;

            if (mt != null)
            {
                if (mt is CLRObject)
                {
                    object tmp = ((CLRObject)mt).inst;
                    if (obType.IsInstanceOfType(tmp))
                    {
                        result = tmp;
                        return(true);
                    }
                    Exceptions.SetError(Exceptions.TypeError, $"value cannot be converted to {obType}");
                    return(false);
                }
                if (mt is ClassBase)
                {
                    var cb = (ClassBase)mt;
                    if (!cb.type.Valid)
                    {
                        Exceptions.SetError(Exceptions.TypeError, cb.type.DeletedMessage);
                        return(false);
                    }
                    result = cb.type.Value;
                    return(true);
                }
                // shouldn't happen
                return(false);
            }

            if (value == Runtime.PyNone && !obType.IsValueType)
            {
                result = null;
                return(true);
            }

            if (obType.IsGenericType && obType.GetGenericTypeDefinition() == typeof(Nullable <>))
            {
                if (value == Runtime.PyNone)
                {
                    result = null;
                    return(true);
                }
                // Set type to underlying type
                obType = obType.GetGenericArguments()[0];
            }

            if (obType.IsArray)
            {
                return(ToArray(value, obType, out result, setError));
            }

            if (obType.IsEnum)
            {
                return(ToEnum(value, obType, out result, setError));
            }

            // Conversion to 'Object' is done based on some reasonable default
            // conversions (Python string -> managed string, Python int -> Int32 etc.).
            if (obType == objectType)
            {
                if (Runtime.IsStringType(value))
                {
                    return(ToPrimitive(value, stringType, out result, setError));
                }

                if (Runtime.PyBool_Check(value))
                {
                    return(ToPrimitive(value, boolType, out result, setError));
                }

                if (Runtime.PyInt_Check(value))
                {
                    return(ToPrimitive(value, int32Type, out result, setError));
                }

                if (Runtime.PyLong_Check(value))
                {
                    return(ToPrimitive(value, int64Type, out result, setError));
                }

                if (Runtime.PyFloat_Check(value))
                {
                    return(ToPrimitive(value, doubleType, out result, setError));
                }

                // give custom codecs a chance to take over conversion of sequences
                IntPtr pyType = Runtime.PyObject_TYPE(value);
                if (PyObjectConversions.TryDecode(value, pyType, obType, out result))
                {
                    return(true);
                }

                if (Runtime.PySequence_Check(value))
                {
                    return(ToArray(value, typeof(object[]), out result, setError));
                }

                Runtime.XIncref(value); // PyObject() assumes ownership
                result = new PyObject(value);
                return(true);
            }

            // Conversion to 'Type' is done using the same mappings as above for objects.
            if (obType == typeType)
            {
                if (value == Runtime.PyStringType)
                {
                    result = stringType;
                    return(true);
                }

                if (value == Runtime.PyBoolType)
                {
                    result = boolType;
                    return(true);
                }

                if (value == Runtime.PyIntType)
                {
                    result = int32Type;
                    return(true);
                }

                if (value == Runtime.PyLongType)
                {
                    result = int64Type;
                    return(true);
                }

                if (value == Runtime.PyFloatType)
                {
                    result = doubleType;
                    return(true);
                }

                if (value == Runtime.PyListType || value == Runtime.PyTupleType)
                {
                    result = typeof(object[]);
                    return(true);
                }

                if (setError)
                {
                    Exceptions.SetError(Exceptions.TypeError, "value cannot be converted to Type");
                }

                return(false);
            }

            TypeCode typeCode = Type.GetTypeCode(obType);

            if (typeCode == TypeCode.Object)
            {
                IntPtr pyType = Runtime.PyObject_TYPE(value);
                if (PyObjectConversions.TryDecode(value, pyType, obType, out result))
                {
                    return(true);
                }
            }

            return(ToPrimitive(value, obType, out result, setError));
        }
Beispiel #3
0
        internal static bool ToManagedValue(BorrowedReference value, Type obType,
                                            out object?result, bool setError)
        {
            if (obType == typeof(PyObject))
            {
                result = new PyObject(value);
                return(true);
            }

            if (obType.IsSubclassOf(typeof(PyObject)) &&
                !obType.IsAbstract &&
                obType.GetConstructor(new[] { typeof(PyObject) }) is { } ctor)
            {
                var untyped = new PyObject(value);
                result = ToPyObjectSubclass(ctor, untyped, setError);
                return(result is not null);
            }

            // Common case: if the Python value is a wrapped managed object
            // instance, just return the wrapped object.
            result = null;
            switch (ManagedType.GetManagedObject(value))
            {
            case CLRObject co:
                object tmp = co.inst;
                if (obType.IsInstanceOfType(tmp))
                {
                    result = tmp;
                    return(true);
                }
                if (setError)
                {
                    string typeString = tmp is null ? "null" : tmp.GetType().ToString();
                    Exceptions.SetError(Exceptions.TypeError, $"{typeString} value cannot be converted to {obType}");
                }
                return(false);

            case ClassBase cb:
                if (!cb.type.Valid)
                {
                    Exceptions.SetError(Exceptions.TypeError, cb.type.DeletedMessage);
                    return(false);
                }
                result = cb.type.Value;
                return(true);

            case null:
                break;

            default:
                throw new ArgumentException("We should never receive instances of other managed types");
            }

            if (value == Runtime.PyNone && !obType.IsValueType)
            {
                result = null;
                return(true);
            }

            if (obType.IsGenericType && obType.GetGenericTypeDefinition() == typeof(Nullable <>))
            {
                if (value == Runtime.PyNone)
                {
                    result = null;
                    return(true);
                }
                // Set type to underlying type
                obType = obType.GetGenericArguments()[0];
            }

            if (obType.ContainsGenericParameters)
            {
                if (setError)
                {
                    Exceptions.SetError(Exceptions.TypeError, $"Cannot create an instance of the open generic type {obType}");
                }
                return(false);
            }

            if (obType.IsArray)
            {
                return(ToArray(value, obType, out result, setError));
            }

            // Conversion to 'Object' is done based on some reasonable default
            // conversions (Python string -> managed string).
            if (obType == objectType)
            {
                if (Runtime.IsStringType(value))
                {
                    return(ToPrimitive(value, stringType, out result, setError));
                }

                if (Runtime.PyBool_Check(value))
                {
                    return(ToPrimitive(value, boolType, out result, setError));
                }

                if (Runtime.PyFloat_Check(value))
                {
                    return(ToPrimitive(value, doubleType, out result, setError));
                }

                // give custom codecs a chance to take over conversion of ints and sequences
                BorrowedReference pyType = Runtime.PyObject_TYPE(value);
                if (PyObjectConversions.TryDecode(value, pyType, obType, out result))
                {
                    return(true);
                }

                if (Runtime.PyInt_Check(value))
                {
                    result = new PyInt(value);
                    return(true);
                }

                if (Runtime.PySequence_Check(value))
                {
                    return(ToArray(value, typeof(object[]), out result, setError));
                }

                result = new PyObject(value);
                return(true);
            }

            // Conversion to 'Type' is done using the same mappings as above for objects.
            if (obType == typeType)
            {
                if (value == Runtime.PyStringType)
                {
                    result = stringType;
                    return(true);
                }

                if (value == Runtime.PyBoolType)
                {
                    result = boolType;
                    return(true);
                }

                if (value == Runtime.PyLongType)
                {
                    result = typeof(PyInt);
                    return(true);
                }

                if (value == Runtime.PyFloatType)
                {
                    result = doubleType;
                    return(true);
                }

                if (value == Runtime.PyListType)
                {
                    result = typeof(PyList);
                    return(true);
                }

                if (value == Runtime.PyTupleType)
                {
                    result = typeof(PyTuple);
                    return(true);
                }

                if (setError)
                {
                    Exceptions.SetError(Exceptions.TypeError, "value cannot be converted to Type");
                }

                return(false);
            }

            if (DecodableByUser(obType))
            {
                BorrowedReference pyType = Runtime.PyObject_TYPE(value);
                if (PyObjectConversions.TryDecode(value, pyType, obType, out result))
                {
                    return(true);
                }
            }

            return(ToPrimitive(value, obType, out result, setError));
        }