#pragma warning disable 1591 using System; using System.Linq; using System.Runtime.InteropServices; using System.Collections.Generic; using Eina.Callbacks; using static Eina.HashNativeFunctions; using static Eina.InarrayNativeFunctions; using static Eina.InlistNativeFunctions; using static Eina.NativeCustomExportFunctions; using static Eina.ContainerCommonData; namespace Eina { public enum ElementType { NumericType, StringType, ObjectType }; public static class ContainerCommonData { public static IBaseElementTraits intPtrTraits = null; } [StructLayout(LayoutKind.Sequential)] public struct InlistMem { public IntPtr next {get;set;} public IntPtr prev {get;set;} public IntPtr last {get;set;} } [StructLayout(LayoutKind.Sequential)] public struct InlistNode { public InlistMem __in_list {get;set;} public T Val {get;set;} } public interface IBaseElementTraits { IntPtr ManagedToNativeAlloc(T man); IntPtr ManagedToNativeAllocRef(T man, bool refs); IntPtr ManagedToNativeAllocInlistNode(T man); IntPtr ManagedToNativeAllocInplace(T man); void NativeFree(IntPtr nat); void NativeFreeRef(IntPtr nat, bool unrefs); void NativeFreeInlistNodeElement(IntPtr nat); void NativeFreeInlistNode(IntPtr nat, bool freeElement); void NativeFreeInplace(IntPtr nat); void ResidueFreeInplace(IntPtr nat); T NativeToManaged(IntPtr nat); T NativeToManagedRef(IntPtr nat); T NativeToManagedInlistNode(IntPtr nat); T NativeToManagedInplace(IntPtr nat); IntPtr EinaCompareCb(); IntPtr EinaFreeCb(); IntPtr EinaHashNew(); IntPtr EinaInarrayNew(uint step); IntPtr EinaHashIteratorKeyNew(IntPtr hash); } public class StringElementTraits : IBaseElementTraits { public StringElementTraits() { if (intPtrTraits == null) intPtrTraits = TraitFunctions.GetTypeTraits(); } public IntPtr ManagedToNativeAlloc(T man) { return MemoryNative.StrDup((string)(object)man); } public IntPtr ManagedToNativeAllocRef(T man, bool refs) { // Keep alloc on C# ? return ManagedToNativeAlloc(man); } public IntPtr ManagedToNativeAllocInlistNode(T man) { var node = new InlistNode(); node.Val = ManagedToNativeAlloc(man); GCHandle pinnedData = GCHandle.Alloc(node, GCHandleType.Pinned); IntPtr ptr = pinnedData.AddrOfPinnedObject(); IntPtr nat = MemoryNative.AllocCopy(ptr, Marshal.SizeOf >()); pinnedData.Free(); return nat; } public IntPtr ManagedToNativeAllocInplace(T man) { return intPtrTraits.ManagedToNativeAlloc(ManagedToNativeAlloc(man)); } public void NativeFree(IntPtr nat) { if (nat != IntPtr.Zero) MemoryNative.Free(nat); } public void NativeFreeRef(IntPtr nat, bool unrefs) { NativeFree(nat); } public void NativeFreeInlistNodeElement(IntPtr nat) { if (nat == IntPtr.Zero) return; var node = Marshal.PtrToStructure< InlistNode >(nat); NativeFree(node.Val); } public void NativeFreeInlistNode(IntPtr nat, bool freeElement) { if (nat == IntPtr.Zero) return; if (freeElement) NativeFreeInlistNodeElement(nat); MemoryNative.Free(nat); } public void NativeFreeInplace(IntPtr nat) { MemoryNative.FreeRef(nat); } public void ResidueFreeInplace(IntPtr nat) { intPtrTraits.NativeFree(nat); } public T NativeToManaged(IntPtr nat) { if (nat == IntPtr.Zero) return default(T); return (T)(object)StringConversion.NativeUtf8ToManagedString(nat); } public T NativeToManagedRef(IntPtr nat) { return NativeToManaged(nat); } public T NativeToManagedInlistNode(IntPtr nat) { if (nat == IntPtr.Zero) { Eina.Log.Error("Null pointer for Inlist node."); return default(T); } var w = Marshal.PtrToStructure< InlistNode >(nat); return NativeToManaged(w.Val); } public T NativeToManagedInplace(IntPtr nat) { if (nat == IntPtr.Zero) return default(T); return NativeToManaged(intPtrTraits.NativeToManaged(nat)); } public IntPtr EinaCompareCb() { return MemoryNative.StrCompareFuncPtrGet(); } public IntPtr EinaFreeCb() { return MemoryNative.FreeFuncPtrGet(); } public IntPtr EinaHashNew() { return eina_hash_string_superfast_new(IntPtr.Zero); } public IntPtr EinaInarrayNew(uint step) { return eina_inarray_new((uint)Marshal.SizeOf(), step); } public IntPtr EinaHashIteratorKeyNew(IntPtr hash) { return eina_hash_iterator_key_new(hash); } } public class EflObjectElementTraits : IBaseElementTraits { private System.Type concreteType = null; public EflObjectElementTraits(System.Type concrete) { if (intPtrTraits == null) intPtrTraits = TraitFunctions.GetTypeTraits(); concreteType = concrete; } public IntPtr ManagedToNativeAlloc(T man) { IntPtr h = ((Efl.Eo.IWrapper)man).NativeHandle; if (h == IntPtr.Zero) return h; return Efl.Eo.Globals.efl_ref(h); } public IntPtr ManagedToNativeAllocRef(T man, bool refs) { IntPtr h = refs ? ManagedToNativeAlloc(man) : ((Efl.Eo.IWrapper)man).NativeHandle; return intPtrTraits.ManagedToNativeAlloc(h); } public IntPtr ManagedToNativeAllocInlistNode(T man) { var node = new InlistNode(); node.Val = ManagedToNativeAlloc(man); GCHandle pinnedData = GCHandle.Alloc(node, GCHandleType.Pinned); IntPtr ptr = pinnedData.AddrOfPinnedObject(); IntPtr nat = MemoryNative.AllocCopy(ptr, Marshal.SizeOf >()); pinnedData.Free(); return nat; } public IntPtr ManagedToNativeAllocInplace(T man) { return intPtrTraits.ManagedToNativeAlloc(ManagedToNativeAlloc(man)); } public void NativeFree(IntPtr nat) { if (nat != IntPtr.Zero) Efl.Eo.Globals.efl_unref(nat); } public void NativeFreeRef(IntPtr nat, bool unrefs) { if (unrefs) NativeFree(intPtrTraits.NativeToManaged(nat)); intPtrTraits.NativeFree(nat); } public void NativeFreeInlistNodeElement(IntPtr nat) { if (nat == IntPtr.Zero) return; var node = Marshal.PtrToStructure< InlistNode >(nat); NativeFree(node.Val); } public void NativeFreeInlistNode(IntPtr nat, bool freeElement) { if (nat == IntPtr.Zero) return; if (freeElement) NativeFreeInlistNodeElement(nat); MemoryNative.Free(nat); } public void NativeFreeInplace(IntPtr nat) { NativeFree(intPtrTraits.NativeToManaged(nat)); } public void ResidueFreeInplace(IntPtr nat) { intPtrTraits.NativeFree(nat); } public T NativeToManaged(IntPtr nat) { if (nat == IntPtr.Zero) return default(T); return (T) Activator.CreateInstance(concreteType, Efl.Eo.Globals.efl_ref(nat)); } public T NativeToManagedRef(IntPtr nat) { if (nat == IntPtr.Zero) return default(T); return NativeToManaged(intPtrTraits.NativeToManaged(nat)); } public T NativeToManagedInlistNode(IntPtr nat) { if (nat == IntPtr.Zero) { Eina.Log.Error("Null pointer for Inlist node."); return default(T); } var w = Marshal.PtrToStructure< InlistNode >(nat); return NativeToManaged(w.Val); } public T NativeToManagedInplace(IntPtr nat) { if (nat == IntPtr.Zero) return default(T); return NativeToManaged(intPtrTraits.NativeToManaged(nat)); } public IntPtr EinaCompareCb() { return MemoryNative.PtrCompareFuncPtrGet(); } public IntPtr EinaFreeCb() { return MemoryNative.EflUnrefFuncPtrGet(); } public IntPtr EinaHashNew() { return eina_hash_pointer_new(IntPtr.Zero); } public IntPtr EinaInarrayNew(uint step) { return eina_inarray_new((uint)Marshal.SizeOf(), step); } public IntPtr EinaHashIteratorKeyNew(IntPtr hash) { return eina_hash_iterator_ptr_key_wrapper_new_custom_export_mono(hash); } } public abstract class PrimitiveElementTraits { private Eina_Compare_Cb dlgt = null; public IntPtr ManagedToNativeAlloc(T man) { return PrimitiveConversion.ManagedToPointerAlloc(man); } public IntPtr ManagedToNativeAllocInlistNode(T man) { var node = new InlistNode(); node.Val = man; GCHandle pinnedData = GCHandle.Alloc(node, GCHandleType.Pinned); IntPtr ptr = pinnedData.AddrOfPinnedObject(); IntPtr nat = MemoryNative.AllocCopy(ptr, Marshal.SizeOf< InlistNode >()); pinnedData.Free(); return nat; } public IntPtr ManagedToNativeAllocInplace(T man) { return ManagedToNativeAlloc(man); } public void NativeFree(IntPtr nat) { MemoryNative.Free(nat); } public void NativeFreeInlistNodeElement(IntPtr nat) { // Do nothing } public void NativeFreeInlistNode(IntPtr nat, bool freeElement) { MemoryNative.Free(nat); } public void NativeFreeInplace(IntPtr nat) { // Do nothing } public void ResidueFreeInplace(IntPtr nat) { NativeFree(nat); } public T NativeToManaged(IntPtr nat) { if (nat == IntPtr.Zero) { Eina.Log.Error("Null pointer on primitive/struct container."); return default(T); } return PrimitiveConversion.PointerToManaged(nat); } public T NativeToManagedRef(IntPtr nat) { return NativeToManaged(nat); } public T NativeToManagedInlistNode(IntPtr nat) { if (nat == IntPtr.Zero) { Eina.Log.Error("Null pointer for Inlist node."); return default(T); } var w = Marshal.PtrToStructure< InlistNode >(nat); return w.Val; } public T NativeToManagedInplace(IntPtr nat) { return NativeToManaged(nat); } private int PrimitiveCompareCb(IntPtr ptr1, IntPtr ptr2) { var m1 = (IComparable) NativeToManaged(ptr1); var m2 = NativeToManaged(ptr2); return m1.CompareTo(m2); } public IntPtr EinaCompareCb() { if (dlgt == null) dlgt = new Eina_Compare_Cb(PrimitiveCompareCb); return Marshal.GetFunctionPointerForDelegate(dlgt); } public IntPtr EinaFreeCb() { return MemoryNative.FreeFuncPtrGet(); } public IntPtr EinaInarrayNew(uint step) { return eina_inarray_new((uint)Marshal.SizeOf(), step); } public IntPtr EinaHashIteratorKeyNew(IntPtr hash) { return eina_hash_iterator_key_new(hash); } } public class Primitive32ElementTraits : PrimitiveElementTraits, IBaseElementTraits { private static IBaseElementTraits int32Traits = null; public Primitive32ElementTraits() { if (int32Traits == null) if (typeof(T) == typeof(Int32)) // avoid infinite recursion int32Traits = (IBaseElementTraits)this; else int32Traits = TraitFunctions.GetTypeTraits(); } public IntPtr ManagedToNativeAllocRef(T man, bool refs) { return int32Traits.ManagedToNativeAlloc(Convert.ToInt32((object)man)); } public void NativeFreeRef(IntPtr nat, bool unrefs) { int32Traits.NativeFree(nat); } public IntPtr EinaHashNew() { return eina_hash_int32_new(IntPtr.Zero); } } public class Primitive64ElementTraits : PrimitiveElementTraits, IBaseElementTraits { private static IBaseElementTraits int64Traits = null; public Primitive64ElementTraits() { if (int64Traits == null) if (typeof(T) == typeof(Int64)) // avoid infinite recursion int64Traits = (IBaseElementTraits)this; else int64Traits = TraitFunctions.GetTypeTraits(); } public IntPtr ManagedToNativeAllocRef(T man, bool refs) { return int64Traits.ManagedToNativeAlloc(Convert.ToInt64((object)man)); } public void NativeFreeRef(IntPtr nat, bool unrefs) { int64Traits.NativeFree(nat); } public IntPtr EinaHashNew() { return eina_hash_int64_new(IntPtr.Zero); } } public static class TraitFunctions { public static bool IsEflObject(System.Type type) { return typeof(Efl.Eo.IWrapper).IsAssignableFrom(type); } public static bool IsString(System.Type type) { return type == typeof(string); } public static Eina.ElementType GetElementTypeCode(System.Type type) { if (IsEflObject(type)) return ElementType.ObjectType; else if (IsString(type)) return ElementType.StringType; else return ElementType.NumericType; } private static IDictionary register = new Dictionary(); private static System.Type AsEflInstantiableType(System.Type type) { if (!IsEflObject(type)) return null; if (type.IsInterface) { string[] names = type.FullName.Split('.'); names[names.Count() - 1] = names.Last().Substring(1); // Remove the leading 'I' (What about user-defined interfaces?) string fullName = string.Join(".", names); return type.Assembly.GetType(fullName); // That was our best guess... } System.Type current = type; while (current != null) { if (current.Name.EndsWith("Inherit")) throw new Exception("Inherit-based classes are not currently supported."); current = current.BaseType; } return type; // Not inherited neither interface, so it should be a concrete. } public static object RegisterTypeTraits() { object traits; var type = typeof(T); if (IsEflObject(type)) { System.Type concrete = AsEflInstantiableType(type); if (concrete == null || !type.IsAssignableFrom(concrete)) throw new Exception("Failed to get a suitable concrete class for this type."); traits = new EflObjectElementTraits(concrete); } else if (IsString(type)) traits = new StringElementTraits(); else if (type.IsValueType) { if (Marshal.SizeOf() <= 4) traits = new Primitive32ElementTraits(); else traits = new Primitive64ElementTraits(); } else throw new Exception("No traits registered for this type"); register[type] = traits; return traits; } public static object RegisterTypeTraits(IBaseElementTraits traits) { register[typeof(T)] = traits; return traits; } public static IBaseElementTraits GetTypeTraits() { object traits; if (!register.TryGetValue(typeof(T), out traits)) traits = RegisterTypeTraits(); return (IBaseElementTraits) traits; } // // // Traits functions // // // // Convertion functions // public static IntPtr ManagedToNativeAlloc(T man) { return GetTypeTraits().ManagedToNativeAlloc(man); } public static IntPtr ManagedToNativeAllocRef(T man, bool refs = false) { return GetTypeTraits().ManagedToNativeAllocRef(man, refs); } public static IntPtr ManagedToNativeAllocInplace(T man) { return GetTypeTraits().ManagedToNativeAllocInplace(man); } public static IntPtr ManagedToNativeAllocInlistNode(T man) { return GetTypeTraits().ManagedToNativeAllocInlistNode(man); } public static void NativeFree(IntPtr nat) { GetTypeTraits().NativeFree(nat); } public static void NativeFreeRef(IntPtr nat, bool unrefs = false) { GetTypeTraits().NativeFreeRef(nat, unrefs); } public static void NativeFreeInlistNodeElement(IntPtr nat) { GetTypeTraits().NativeFreeInlistNodeElement(nat); } public static void NativeFreeInlistNode(IntPtr nat, bool freeElement = true) { GetTypeTraits().NativeFreeInlistNode(nat, freeElement); } public static void NativeFreeInplace(IntPtr nat) { GetTypeTraits().NativeFreeInplace(nat); } public static void ResidueFreeInplace(IntPtr nat) { GetTypeTraits().ResidueFreeInplace(nat); } public static T NativeToManaged(IntPtr nat) { return GetTypeTraits().NativeToManaged(nat); } public static T NativeToManagedRef(IntPtr nat) { return GetTypeTraits().NativeToManagedRef(nat); } public static T NativeToManagedInlistNode(IntPtr nat) { return GetTypeTraits().NativeToManagedInlistNode(nat); } public static T NativeToManagedInplace(IntPtr nat) { return GetTypeTraits().NativeToManagedInplace(nat); } // Misc // public static IntPtr EinaCompareCb() { return GetTypeTraits().EinaCompareCb(); } public static IntPtr EinaFreeCb() { return GetTypeTraits().EinaFreeCb(); } public static IntPtr EinaHashNew() { return GetTypeTraits().EinaHashNew(); } public static IntPtr EinaInarrayNew(uint step) { return GetTypeTraits().EinaInarrayNew(step); } public static IntPtr EinaHashIteratorKeyNew(IntPtr hash) { return GetTypeTraits().EinaHashIteratorKeyNew(hash); } } }