1 #pragma warning disable 1591
5 using System.Runtime.InteropServices;
6 using System.Collections.Generic;
7 using System.Reflection;
10 using static Eina.HashNativeFunctions;
11 using static Eina.InarrayNativeFunctions;
12 using static Eina.InlistNativeFunctions;
13 using static Eina.NativeCustomExportFunctions;
18 public enum ElementType
25 [StructLayout(LayoutKind.Sequential)]
26 public struct InlistMem
28 public IntPtr next {get;set;}
29 public IntPtr prev {get;set;}
30 public IntPtr last {get;set;}
33 [StructLayout(LayoutKind.Sequential)]
34 public struct InlistNode<T>
36 public InlistMem __in_list {get;set;}
37 public T Val {get;set;}
40 public interface IBaseElementTraits<T>
42 IntPtr ManagedToNativeAlloc(T man);
43 IntPtr ManagedToNativeAllocInlistNode(T man);
44 void ManagedToNativeCopyTo(T man, IntPtr mem);
45 void NativeFree(IntPtr nat);
46 void NativeFreeInlistNodeElement(IntPtr nat);
47 void NativeFreeInlistNode(IntPtr nat, bool freeElement);
48 void NativeFreeInplace(IntPtr nat);
49 void ResidueFreeInplace(IntPtr nat);
50 T NativeToManaged(IntPtr nat);
51 T NativeToManagedInlistNode(IntPtr nat);
52 T NativeToManagedInplace(IntPtr nat);
53 IntPtr EinaCompareCb();
56 IntPtr EinaInarrayNew(uint step);
57 IntPtr EinaHashIteratorKeyNew(IntPtr hash);
60 public class StringElementTraits : IBaseElementTraits<string>
62 public StringElementTraits()
66 public IntPtr ManagedToNativeAlloc(string man)
68 IntPtr newstring = MemoryNative.StrDup(man);
72 public IntPtr ManagedToNativeAllocInlistNode(string man)
74 var node = new InlistNode<IntPtr>();
75 node.Val = ManagedToNativeAlloc(man);
76 GCHandle pinnedData = GCHandle.Alloc(node, GCHandleType.Pinned);
77 IntPtr ptr = pinnedData.AddrOfPinnedObject();
78 IntPtr nat = MemoryNative.AllocCopy(ptr, Marshal.SizeOf<InlistMem>() + Marshal.SizeOf<IntPtr>());
83 public void ManagedToNativeCopyTo(string man, IntPtr mem)
85 IntPtr stringptr = ManagedToNativeAlloc(man);
86 Marshal.WriteIntPtr(mem, stringptr);
89 public void NativeFree(IntPtr nat)
91 if (nat != IntPtr.Zero)
93 MemoryNative.Free(nat);
97 public void NativeFreeInlistNodeElement(IntPtr nat)
99 if (nat == IntPtr.Zero)
104 var val = Marshal.PtrToStructure<IntPtr>
105 (nat + Marshal.SizeOf<InlistMem>());
109 public void NativeFreeInlistNode(IntPtr nat, bool freeElement)
111 if (nat == IntPtr.Zero)
118 NativeFreeInlistNodeElement(nat);
121 MemoryNative.Free(nat);
124 public void NativeFreeInplace(IntPtr nat)
126 MemoryNative.FreeRef(nat);
129 public void ResidueFreeInplace(IntPtr nat)
133 public string NativeToManaged(IntPtr nat)
135 if (nat == IntPtr.Zero)
137 return default(string);
140 return StringConversion.NativeUtf8ToManagedString(nat);
143 public string NativeToManagedInlistNode(IntPtr nat)
145 if (nat == IntPtr.Zero)
147 Eina.Log.Error("Null pointer for Inlist node.");
148 return default(string);
151 IntPtr ptr_location = nat + Marshal.SizeOf<InlistMem>();
152 return NativeToManaged(Marshal.ReadIntPtr(ptr_location));
155 // Strings inplaced are always a pointer, because they are variable-sized
156 public string NativeToManagedInplace(IntPtr nat)
158 if (nat == IntPtr.Zero)
160 return default(string);
163 nat = Marshal.ReadIntPtr(nat);
164 if (nat == IntPtr.Zero)
166 return default(string);
169 return NativeToManaged(nat);
172 public IntPtr EinaCompareCb()
174 return MemoryNative.StrCompareFuncPtrGet();
177 public IntPtr EinaFreeCb()
179 return MemoryNative.FreeFuncPtrGet();
182 public IntPtr EinaHashNew()
184 return eina_hash_string_superfast_new(IntPtr.Zero);
187 public IntPtr EinaInarrayNew(uint step)
189 return eina_inarray_new((uint)Marshal.SizeOf<IntPtr>(), step);
192 public IntPtr EinaHashIteratorKeyNew(IntPtr hash)
194 return eina_hash_iterator_key_new(hash);
198 public class EflObjectElementTraits<T> : IBaseElementTraits<T>
200 public IntPtr ManagedToNativeAlloc(T man)
202 IntPtr h = ((Efl.Eo.IWrapper)man).NativeHandle;
203 if (h == IntPtr.Zero)
208 return Efl.Eo.Globals.efl_ref(h);
211 public IntPtr ManagedToNativeAllocInlistNode(T man)
213 var node = new InlistNode<IntPtr>();
214 node.Val = ManagedToNativeAlloc(man);
215 GCHandle pinnedData = GCHandle.Alloc(node, GCHandleType.Pinned);
216 IntPtr ptr = pinnedData.AddrOfPinnedObject();
217 IntPtr nat = MemoryNative.AllocCopy(ptr, Marshal.SizeOf<InlistMem>() + Marshal.SizeOf<IntPtr>());
222 public void ManagedToNativeCopyTo(T man, IntPtr mem)
224 IntPtr v = ManagedToNativeAlloc(man);
225 Marshal.WriteIntPtr(mem, v);
228 public void NativeFree(IntPtr nat)
230 if (nat != IntPtr.Zero)
232 Efl.Eo.Globals.efl_mono_thread_safe_efl_unref(nat);
236 public void NativeFreeRef(IntPtr nat, bool unrefs)
244 public void NativeFreeInlistNodeElement(IntPtr nat)
246 if (nat == IntPtr.Zero)
251 var val = Marshal.PtrToStructure<IntPtr>
252 (nat + Marshal.SizeOf<InlistMem>());
256 public void NativeFreeInlistNode(IntPtr nat, bool freeElement)
258 if (nat == IntPtr.Zero)
265 NativeFreeInlistNodeElement(nat);
268 MemoryNative.Free(nat);
271 public void NativeFreeInplace(IntPtr nat)
276 public void ResidueFreeInplace(IntPtr nat)
280 public T NativeToManaged(IntPtr nat)
282 if (nat == IntPtr.Zero)
287 return (T) Efl.Eo.Globals.CreateWrapperFor(nat, shouldIncRef: true);
290 public T NativeToManagedRef(IntPtr nat)
292 if (nat == IntPtr.Zero)
297 return NativeToManaged(nat);
300 public T NativeToManagedInlistNode(IntPtr nat)
302 if (nat == IntPtr.Zero)
304 Eina.Log.Error("Null pointer for Inlist node.");
308 IntPtr ptr_location = nat + Marshal.SizeOf<InlistMem>();
309 return NativeToManaged(Marshal.ReadIntPtr(ptr_location));
312 // EFL objects inplaced are always a pointer, because they are variable-sized
313 public T NativeToManagedInplace(IntPtr nat)
315 if (nat == IntPtr.Zero)
320 nat = Marshal.ReadIntPtr(nat);
321 if (nat == IntPtr.Zero)
326 return NativeToManaged(nat);
329 public IntPtr EinaCompareCb()
331 return MemoryNative.PtrCompareFuncPtrGet();
334 public IntPtr EinaFreeCb()
336 return MemoryNative.EflUnrefFuncPtrGet();
339 public IntPtr EinaHashNew()
341 return eina_hash_pointer_new(IntPtr.Zero);
344 public IntPtr EinaInarrayNew(uint step)
346 return eina_inarray_new((uint)Marshal.SizeOf<IntPtr>(), step);
349 public IntPtr EinaHashIteratorKeyNew(IntPtr hash)
351 return eina_hash_iterator_ptr_key_wrapper_new_custom_export_mono(hash);
355 public abstract class PrimitiveElementTraits<T>
357 private Eina_Compare_Cb dlgt = null;
359 public IntPtr ManagedToNativeAlloc(T man)
361 return PrimitiveConversion.ManagedToPointerAlloc(man);
364 public IntPtr ManagedToNativeAllocInlistNode(T man)
366 var node = new InlistNode<T>();
368 GCHandle pinnedData = GCHandle.Alloc(node, GCHandleType.Pinned);
369 IntPtr ptr = pinnedData.AddrOfPinnedObject();
370 int Tsize = Marshal.SizeOf<T>() < Marshal.SizeOf<IntPtr>() ? Marshal.SizeOf<IntPtr>() : Marshal.SizeOf<T>();
371 IntPtr nat = MemoryNative.AllocCopy(ptr, Marshal.SizeOf<InlistMem>() + Tsize);
376 public void NativeFree(IntPtr nat)
378 MemoryNative.Free(nat);
381 public void NativeFreeInlistNodeElement(IntPtr nat)
386 public void NativeFreeInlistNode(IntPtr nat, bool freeElement)
388 MemoryNative.Free(nat);
391 public void NativeFreeInplace(IntPtr nat)
396 public void ResidueFreeInplace(IntPtr nat)
401 public T NativeToManaged(IntPtr nat)
403 if (nat == IntPtr.Zero)
405 Eina.Log.Error("Null pointer on primitive/struct container.");
409 return PrimitiveConversion.PointerToManaged<T>(nat);
412 public T NativeToManagedRef(IntPtr nat)
414 return NativeToManaged(nat);
418 public T NativeToManagedInplace(IntPtr nat)
420 return NativeToManaged(nat);
423 private int PrimitiveCompareCb(IntPtr ptr1, IntPtr ptr2)
425 var m1 = (IComparable)NativeToManaged(ptr1);
426 var m2 = NativeToManaged(ptr2);
427 return m1.CompareTo(m2);
430 public IntPtr EinaCompareCb()
434 dlgt = new Eina_Compare_Cb(PrimitiveCompareCb);
437 return Marshal.GetFunctionPointerForDelegate(dlgt);
440 public IntPtr EinaFreeCb()
442 return MemoryNative.FreeFuncPtrGet();
445 public IntPtr EinaInarrayNew(uint step)
447 return eina_inarray_new((uint)Marshal.SizeOf<T>(), step);
450 public IntPtr EinaHashIteratorKeyNew(IntPtr hash)
452 return eina_hash_iterator_key_new(hash);
456 abstract public class Primitive32ElementTraits<T> : PrimitiveElementTraits<T>, IBaseElementTraits<T>
458 private static IBaseElementTraits<Int32> int32Traits = null;
460 public Primitive32ElementTraits()
462 if (int32Traits == null)
464 if (typeof(T) == typeof(Int32)) // avoid infinite recursion
466 int32Traits = (IBaseElementTraits<Int32>)this;
470 int32Traits = TraitFunctions.GetTypeTraits<Int32>();
475 public abstract void ManagedToNativeCopyTo(T man, IntPtr mem);
476 public abstract T NativeToManagedInlistNode(IntPtr nat);
478 public IntPtr ManagedToNativeAllocRef(T man, bool refs)
480 return int32Traits.ManagedToNativeAlloc(Convert.ToInt32((object)man));
483 public void NativeFreeRef(IntPtr nat, bool unrefs)
485 int32Traits.NativeFree(nat);
488 public IntPtr EinaHashNew()
490 return eina_hash_int32_new(IntPtr.Zero);
494 abstract public class Primitive64ElementTraits<T> : PrimitiveElementTraits<T>, IBaseElementTraits<T>
496 private static IBaseElementTraits<Int64> int64Traits = null;
498 public Primitive64ElementTraits()
500 if (int64Traits == null)
502 if (typeof(T) == typeof(Int64)) // avoid infinite recursion
504 int64Traits = (IBaseElementTraits<Int64>)this;
508 int64Traits = TraitFunctions.GetTypeTraits<Int64>();
513 public abstract void ManagedToNativeCopyTo(T man, IntPtr mem);
514 public abstract T NativeToManagedInlistNode(IntPtr nat);
516 public IntPtr ManagedToNativeAllocRef(T man, bool refs)
518 return int64Traits.ManagedToNativeAlloc(Convert.ToInt64((object)man));
521 public void NativeFreeRef(IntPtr nat, bool unrefs)
523 int64Traits.NativeFree(nat);
526 public IntPtr EinaHashNew()
528 return eina_hash_int64_new(IntPtr.Zero);
532 public class IntElementTraits : Primitive32ElementTraits<int>, IBaseElementTraits<int>
534 override public void ManagedToNativeCopyTo(int man, IntPtr mem)
536 var arr = new int[1];
538 Marshal.Copy(arr, 0, mem, 1);
541 override public int NativeToManagedInlistNode(IntPtr nat)
543 if (nat == IntPtr.Zero)
545 Eina.Log.Error("Null pointer for Inlist node.");
549 IntPtr loc = nat + Marshal.SizeOf<InlistMem>();
551 Marshal.Copy(loc, v, 0, 1);
556 public class CharElementTraits : Primitive32ElementTraits<char>, IBaseElementTraits<char>
558 override public void ManagedToNativeCopyTo(char man, IntPtr mem)
560 var arr = new char[1];
562 Marshal.Copy(arr, 0, mem, 1);
565 override public char NativeToManagedInlistNode(IntPtr nat)
567 if (nat == IntPtr.Zero)
569 Eina.Log.Error("Null pointer for Inlist node.");
570 return default(char);
573 IntPtr loc = nat + Marshal.SizeOf<InlistMem>();
575 Marshal.Copy(loc, v, 0, 1);
580 public class LongElementTraits : Primitive64ElementTraits<long>, IBaseElementTraits<long>
582 override public void ManagedToNativeCopyTo(long man, IntPtr mem)
584 var arr = new long[1];
586 Marshal.Copy(arr, 0, mem, 1);
589 override public long NativeToManagedInlistNode(IntPtr nat)
591 if (nat == IntPtr.Zero)
593 Eina.Log.Error("Null pointer for Inlist node.");
594 return default(long);
597 IntPtr loc = nat + Marshal.SizeOf<InlistMem>();
599 Marshal.Copy(loc, v, 0, 1);
604 public class ShortElementTraits : Primitive32ElementTraits<short>, IBaseElementTraits<short>
606 override public void ManagedToNativeCopyTo(short man, IntPtr mem)
608 var arr = new short[1];
610 Marshal.Copy(arr, 0, mem, 1);
613 override public short NativeToManagedInlistNode(IntPtr nat)
615 if (nat == IntPtr.Zero)
617 Eina.Log.Error("Null pointer for Inlist node.");
618 return default(short);
621 IntPtr loc = nat + Marshal.SizeOf<InlistMem>();
622 var v = new short[1];
623 Marshal.Copy(loc, v, 0, 1);
628 public class FloatElementTraits : Primitive32ElementTraits<float>, IBaseElementTraits<float>
630 override public void ManagedToNativeCopyTo(float man, IntPtr mem)
632 var arr = new float[1];
634 Marshal.Copy(arr, 0, mem, 1);
637 override public float NativeToManagedInlistNode(IntPtr nat)
639 if (nat == IntPtr.Zero)
641 Eina.Log.Error("Null pointer for Inlist node.");
642 return default(float);
645 IntPtr loc = nat + Marshal.SizeOf<InlistMem>();
646 var v = new float[1];
647 Marshal.Copy(loc, v, 0, 1);
652 public class DoubleElementTraits : Primitive64ElementTraits<double>, IBaseElementTraits<double>
654 override public void ManagedToNativeCopyTo(double man, IntPtr mem)
656 var arr = new double[1];
658 Marshal.Copy(arr, 0, mem, 1);
661 override public double NativeToManagedInlistNode(IntPtr nat)
663 if (nat == IntPtr.Zero)
665 Eina.Log.Error("Null pointer for Inlist node.");
666 return default(double);
669 IntPtr loc = nat + Marshal.SizeOf<InlistMem>();
670 var v = new double[1];
671 Marshal.Copy(loc, v, 0, 1);
676 public class ByteElementTraits : Primitive32ElementTraits<byte>, IBaseElementTraits<byte>
678 override public void ManagedToNativeCopyTo(byte man, IntPtr mem)
680 var arr = new byte[1];
682 Marshal.Copy(arr, 0, mem, 1);
685 override public byte NativeToManagedInlistNode(IntPtr nat)
687 if (nat == IntPtr.Zero)
689 Eina.Log.Error("Null pointer for Inlist node.");
690 return default(byte);
693 IntPtr loc = nat + Marshal.SizeOf<InlistMem>();
695 Marshal.Copy(loc, v, 0, 1);
700 public static class TraitFunctions
702 public static bool IsEflObject(System.Type type)
704 return typeof(Efl.Eo.IWrapper).IsAssignableFrom(type);
707 public static bool IsString(System.Type type)
709 return type == typeof(string);
712 public static Eina.ElementType GetElementTypeCode(System.Type type)
714 if (IsEflObject(type))
716 return ElementType.ObjectType;
718 else if (IsString(type))
720 return ElementType.StringType;
724 return ElementType.NumericType;
728 private static IDictionary<System.Type, object> register = new Dictionary<System.Type, object>();
730 private static System.Type AsEflInstantiableType(System.Type type)
732 if (!IsEflObject(type))
737 if (type.IsInterface)
739 string fullName = type.FullName + "Concrete";
740 return type.Assembly.GetType(fullName); // That was our best guess...
743 return type; // Not interface, so it should be a concrete.
746 public static object RegisterTypeTraits<T>()
748 Eina.Log.Debug($"Finding TypeTraits for {typeof(T).Name}");
750 var type = typeof(T);
751 if (IsEflObject(type))
753 System.Type concrete = AsEflInstantiableType(type);
754 if (concrete == null || !type.IsAssignableFrom(concrete))
756 throw new Exception("Failed to get a suitable concrete class for this type.");
759 // No need to pass concrete as the traits class will use reflection to get the actually most
760 // derived type returned.
761 traits = new EflObjectElementTraits<T>();
763 else if (IsString(type))
765 traits = new StringElementTraits();
767 else if (type.IsValueType)
769 if (type == typeof(int))
771 traits = new IntElementTraits();
773 else if (type == typeof(char))
775 traits = new CharElementTraits();
777 else if (type == typeof(long))
779 traits = new LongElementTraits();
781 else if (type == typeof(short))
783 traits = new ShortElementTraits();
785 else if (type == typeof(float))
787 traits = new FloatElementTraits();
789 else if (type == typeof(double))
791 traits = new DoubleElementTraits();
793 else if (type == typeof(byte))
795 traits = new ByteElementTraits();
799 throw new Exception("No traits registered for this type");
804 throw new Exception("No traits registered for this type");
807 register[type] = traits;
811 public static object RegisterTypeTraits<T>(IBaseElementTraits<T> traits)
813 register[typeof(T)] = traits;
817 public static IBaseElementTraits<T> GetTypeTraits<T>()
820 if (!register.TryGetValue(typeof(T), out traits))
822 traits = RegisterTypeTraits<T>();
825 return (IBaseElementTraits<T>)traits;
829 // Traits functions //
832 // Convertion functions //
834 public static IntPtr ManagedToNativeAlloc<T>(T man)
836 return GetTypeTraits<T>().ManagedToNativeAlloc(man);
839 public static void ManagedToNativeCopyTo<T>(T man, IntPtr mem)
841 GetTypeTraits<T>().ManagedToNativeCopyTo(man, mem);
844 public static IntPtr ManagedToNativeAllocInlistNode<T>(T man)
846 return GetTypeTraits<T>().ManagedToNativeAllocInlistNode(man);
849 public static void NativeFree<T>(IntPtr nat)
851 GetTypeTraits<T>().NativeFree(nat);
854 public static void NativeFreeInlistNodeElement<T>(IntPtr nat)
856 GetTypeTraits<T>().NativeFreeInlistNodeElement(nat);
859 public static void NativeFreeInlistNode<T>(IntPtr nat, bool freeElement = true)
861 GetTypeTraits<T>().NativeFreeInlistNode(nat, freeElement);
864 public static void NativeFreeInplace<T>(IntPtr nat)
866 GetTypeTraits<T>().NativeFreeInplace(nat);
869 public static void ResidueFreeInplace<T>(IntPtr nat)
871 GetTypeTraits<T>().ResidueFreeInplace(nat);
874 public static T NativeToManaged<T>(IntPtr nat)
876 return GetTypeTraits<T>().NativeToManaged(nat);
879 public static T NativeToManagedInlistNode<T>(IntPtr nat)
881 return GetTypeTraits<T>().NativeToManagedInlistNode(nat);
884 public static T NativeToManagedInplace<T>(IntPtr nat)
886 return GetTypeTraits<T>().NativeToManagedInplace(nat);
891 public static IntPtr EinaCompareCb<T>()
893 return GetTypeTraits<T>().EinaCompareCb();
896 public static IntPtr EinaFreeCb<T>()
898 return GetTypeTraits<T>().EinaFreeCb();
901 public static IntPtr EinaHashNew<TKey>()
903 return GetTypeTraits<TKey>().EinaHashNew();
906 public static IntPtr EinaInarrayNew<T>(uint step)
908 return GetTypeTraits<T>().EinaInarrayNew(step);
911 public static IntPtr EinaHashIteratorKeyNew<T>(IntPtr hash)
913 return GetTypeTraits<T>().EinaHashIteratorKeyNew(hash);