[ Web Proxy ]
URL:
Viewing: https://raw.githubusercontent.com/sdpython/pythonnet/master/src/runtime/converterextensions.cs [Back]  [Original]

namespace Python.Runtime
{
    using System;
    using System.Collections.Concurrent;
    using System.Collections.Generic;
    using System.Linq;
    using System.Reflection;
    using Python.Runtime.Codecs;

    /// 
    /// Defines  conversion to CLR types (unmarshalling)
    /// 
    public interface IPyObjectDecoder
    {
        /// 
        /// Checks if this decoder can decode from  to 
        /// 
        bool CanDecode(PyObject objectType, Type targetType);
        /// 
        /// Attempts do decode  into a variable of specified type
        /// 
        /// CLR type to decode into
        /// Object to decode
        /// The variable, that will receive decoding result
        /// 
        bool TryDecode(PyObject pyObj, out T value);
    }

    /// 
    /// Defines conversion from CLR objects into Python objects (e.g. ) (marshalling)
    /// 
    public interface IPyObjectEncoder
    {
        /// 
        /// Checks if encoder can encode CLR objects of specified type
        /// 
        bool CanEncode(Type type);
        /// 
        /// Attempts to encode CLR object  into Python object
        /// 
        PyObject TryEncode(object value);
    }

    /// 
    /// This class allows to register additional marshalling codecs.
    /// Python.NET will pick suitable encoder/decoder registered first
    /// 
    public static class PyObjectConversions
    {
        static readonly DecoderGroup decoders = new DecoderGroup();
        static readonly EncoderGroup encoders = new EncoderGroup();

        /// 
        /// Registers specified encoder (marshaller)
        /// Python.NET will pick suitable encoder/decoder registered first
        /// 
        public static void RegisterEncoder(IPyObjectEncoder encoder)
        {
            if (encoder == null) throw new ArgumentNullException(nameof(encoder));

            lock (encoders)
            {
                encoders.Add(encoder);
            }
        }

        /// 
        /// Registers specified decoder (unmarshaller)
        /// Python.NET will pick suitable encoder/decoder registered first
        /// 
        public static void RegisterDecoder(IPyObjectDecoder decoder)
        {
            if (decoder == null) throw new ArgumentNullException(nameof(decoder));

            lock (decoders)
            {
                decoders.Add(decoder);
            }
        }

        #region Encoding
        internal static PyObject TryEncode(object obj, Type type)
        {
            if (obj == null) throw new ArgumentNullException(nameof(obj));
            if (type == null) throw new ArgumentNullException(nameof(type));

            foreach (var encoder in clrToPython.GetOrAdd(type, GetEncoders))
            {
                var result = encoder.TryEncode(obj);
                if (result != null) return result;
            }

            return null;
        }

        static readonly ConcurrentDictionary
            clrToPython = new ConcurrentDictionary();
        static IPyObjectEncoder[] GetEncoders(Type type)
        {
            lock (encoders)
            {
                return encoders.GetEncoders(type).ToArray();
            }
        }
        #endregion

        #region Decoding
        static readonly ConcurrentDictionary
            pythonToClr = new ConcurrentDictionary();
        internal static bool TryDecode(IntPtr pyHandle, IntPtr pyType, Type targetType, out object result)
        {
            if (pyHandle == IntPtr.Zero) throw new ArgumentNullException(nameof(pyHandle));
            if (pyType == IntPtr.Zero) throw new ArgumentNullException(nameof(pyType));
            if (targetType == null) throw new ArgumentNullException(nameof(targetType));

            var decoder = pythonToClr.GetOrAdd(new TypePair(pyType, targetType), pair => GetDecoder(pair.PyType, pair.ClrType));
            result = null;
            if (decoder == null) return false;
            return decoder.Invoke(pyHandle, out result);
        }

        static Converter.TryConvertFromPythonDelegate GetDecoder(IntPtr sourceType, Type targetType)
        {
            IPyObjectDecoder decoder;
            using (var pyType = new PyObject(Runtime.SelfIncRef(sourceType)))
            {
                lock (decoders)
                {
                    decoder = decoders.GetDecoder(pyType, targetType);
                    if (decoder == null) return null;
                }
            }

            var decode = genericDecode.MakeGenericMethod(targetType);

            bool TryDecode(IntPtr pyHandle, out object result)
            {
                var pyObj = new PyObject(Runtime.SelfIncRef(pyHandle));
                var @params = new object[] { pyObj, null };
                bool success = (bool)decode.Invoke(decoder, @params);
                if (!success)
                {
                    pyObj.Dispose();
                }

                result = @params[1];
                return success;
            }

            return TryDecode;
        }

        static readonly MethodInfo genericDecode = typeof(IPyObjectDecoder).GetMethod(nameof(IPyObjectDecoder.TryDecode));

        #endregion

        internal static void Reset()
        {
            lock (encoders)
                lock (decoders)
                {
                    clrToPython.Clear();
                    pythonToClr.Clear();
                    encoders.Clear();
                    decoders.Clear();
                }
        }

        struct TypePair : IEquatable
        {
            internal readonly IntPtr PyType;
            internal readonly Type ClrType;

            public TypePair(IntPtr pyType, Type clrType)
            {
                this.PyType = pyType;
                this.ClrType = clrType;
            }

            public override int GetHashCode()
                => this.ClrType.GetHashCode() ^ this.PyType.GetHashCode();

            public bool Equals(TypePair other)
                => this.PyType == other.PyType && this.ClrType == other.ClrType;

            public override bool Equals(object obj) => obj is TypePair other && this.Equals(other);
        }
    }
}

Web Proxy Viewer  |  New URL  |  Original Page