X Tutup
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); } } }
X Tutup