Currently C# bindings have explicit Eina
collection classes that are used in
the API. With them, an Eolian method list<int> method(int a, int b)
maps to
the following C# method: Eina.List<int> Method(int a, int b)
.
Instead of exposing the Eina API directly, we could use them disguised as
System.Collection.Generic
interfaces as in the mapping below. The example
above becomes IList<int> Method(int a, int b)
.
Using such interfaces would hide the C details and allow the user passing collections he's more used to.
Meanwhile, the Eina.*
classes could still be exposed but as an optional
implementation of the Collections
interfaces in case the C# developer
wants better performance interacting with the native methods.
Eina class | System.Collection counterpart |
---|---|
Eina.Accessor<T> |
System.Collections.IEnumerable<T> |
Eina.Array<T> |
System.Collections.IList<T> |
Eina.Hash<K,V> |
System.Collections.IDictionary<K, V> |
Eina.Iterator<T> |
System.Collections.IEnumerable<T> |
Eina.List<T> |
System.Collections.IList<T> |
The two main contexts where we have conversions between C# and C are the C# API method wrapper and the EO virtual method wrapper.
This occurs when C# code invokes C code and is the most common one. C# managed data is marshalled to native data and passed to C.
This occurs when a C# method is overriden and called from C code. Umanaged data is marshalled back to C# and C# methods are called.
Special attention must be paid to data that require copying and are given
back to C without @move
to avoid resource leak.
@in
@out
return
- Ownership transferred
- Ownership not tranferred
- Ownership transferred
- Ownership not tranferred
Note: Value types (like
structs
andints
) are always assumed to be owned by their container.
Note: The scenario where the container is not owned but the payload is owned will not be covered as it does not make sense. Shouldn't eolian forbid it?
- Value type
- Strings // mstrings?
- Object
- C# calling C
- C calling C#
Id | Direction | Call Direction | Container moved | Payload moved | Payload | Eolian type |
---|---|---|---|---|---|---|
1 | @in |
Native to Managed | Moved | int | @in list<int>@move |
|
2 | @in |
Native to Managed | int | @in list<int> |
||
3 | @in |
Managed to Native | Moved | int | @in list<int>@move |
|
4 | @in |
Managed to Native | int | @in list<int> |
||
5 | @out |
Native to Managed | Moved | int | @out list<int>@move |
|
6 | @out |
Native to Managed | int | @out list<int> |
||
7 | @out |
Managed to Native | Moved | int | @out list<int>@move |
|
8 | @out |
Managed to Native | int | @out list<int> |
||
9 | return |
Native to Managed | Moved | int | return list<int>@move |
|
10 | return |
Native to Managed | int | return list<int> |
||
11 | return |
Managed to Native | Moved | int | return list<int>@move |
|
12 | return |
Managed to Native | int | return list<int> |
||
13 | @in |
Native to Managed | Moved | Moved | string | @in list<string @move>@move |
14 | @in |
Native to Managed | Moved | string | @in list<string>@move |
|
15 | @in |
Native to Managed | string | @in list<string> |
||
16 | @in |
Managed to Native | Moved | Moved | string | @in list<string @move>@move |
17 | @in |
Managed to Native | Moved | string | @in list<string>@move |
|
18 | @in |
Managed to Native | string | @in list<string> |
||
19 | @out |
Native to Managed | Moved | Moved | string | @out list<string @move>@move |
20 | @out |
Native to Managed | Moved | string | @out list<string>@move |
|
21 | @out |
Native to Managed | string | @out list<string> |
||
22 | @out |
Managed to Native | Moved | Moved | string | @out list<string @move>@move |
23 | @out |
Managed to Native | Moved | string | @out list<string>@move |
|
24 | @out |
Managed to Native | string | @out list<string> |
||
25 | return |
Native to Managed | Moved | Moved | string | return list<string @move>@move |
26 | return |
Native to Managed | Moved | string | return list<string>@move |
|
27 | return |
Native to Managed | string | return list<string> |
||
28 | return |
Managed to Native | Moved | Moved | string | return list<string @move>@move |
29 | return |
Managed to Native | Moved | string | return list<string>@move |
|
30 | return |
Managed to Native | string | return list<string> |
||
31 | @in |
Native to Managed | Moved | Moved | Efl.Object | @in list<Efl.Object @move>@move |
32 | @in |
Native to Managed | Moved | Efl.Object | @in list<Efl.Object>@move |
|
33 | @in |
Native to Managed | Efl.Object | @in list<Efl.Object> |
||
34 | @in |
Managed to Native | Moved | Moved | Efl.Object | @in list<Efl.Object @move>@move |
35 | @in |
Managed to Native | Moved | Efl.Object | @in list<Efl.Object>@move |
|
36 | @in |
Managed to Native | Efl.Object | @in list<Efl.Object> |
||
37 | @out |
Native to Managed | Moved | Moved | Efl.Object | @out list<Efl.Object @move>@move |
38 | @out |
Native to Managed | Moved | Efl.Object | @out list<Efl.Object>@move |
|
39 | @out |
Native to Managed | Efl.Object | @out list<Efl.Object> |
||
40 | @out |
Managed to Native | Moved | Moved | Efl.Object | @out list<Efl.Object @move>@move |
41 | @out |
Managed to Native | Moved | Efl.Object | @out list<Efl.Object>@move |
|
42 | @out |
Managed to Native | Efl.Object | @out list<Efl.Object> |
||
43 | return |
Native to Managed | Moved | Moved | Efl.Object | return list<Efl.Object @move>@move |
44 | return |
Native to Managed | Moved | Efl.Object | return list<Efl.Object>@move |
|
45 | return |
Native to Managed | Efl.Object | return list<Efl.Object> |
||
46 | return |
Managed to Native | Moved | Moved | Efl.Object | return list<Efl.Object @move>@move |
47 | return |
Managed to Native | Moved | Efl.Object | return list<Efl.Object>@move |
|
48 | return |
Managed to Native | Efl.Object | return list<Efl.Object> |
These scenarios will use list<t>
as the container in the examples
In the C# wrapper, an Eina.List<T>
is created and returned as an IList<T>
back to C#, owning the native list so it can be freed.
In the virtual method wrapper, we check if the IList<T>
is actually an
Eina.List<T>
. If positive, just pass the pointer ahead, making
In the C# wrapper, an Eina.List<T>
is created and returned as an IList<T>
back to C#, not owning the native list.
NOTE: With this approach, the native list could be deleted while the C# wrapper is still used, leading to problems. Should we copy the returned list into a C#-owned list?