Skip to content

Instantly share code, notes, and snippets.

@lauromoura
Created November 28, 2019 22:53
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save lauromoura/2613b5db9d01211a219d39850a990f0f to your computer and use it in GitHub Desktop.
Save lauromoura/2613b5db9d01211a219d39850a990f0f to your computer and use it in GitHub Desktop.
Some notes about collection changes in EFL#

Eina collections replacement

Current approach

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).

Proposal

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.

Mapping between Eina classes and System.Collections ones

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>

Two main contexts of data marshalling

The two main contexts where we have conversions between C# and C are the C# API method wrapper and the EO virtual method wrapper.

C# API 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.

EO virtual method wrapper

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.

Variables

Parameter direction

  1. @in
  2. @out
  3. return

Container ownership

  1. Ownership transferred
  2. Ownership not tranferred

Payload ownership - Reference types only

  1. Ownership transferred
  2. Ownership not tranferred

Note: Value types (like structs and ints) 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?

Kind of content

  1. Value type
  2. Strings // mstrings?
  3. Object

Call direction

  1. C# calling C
  2. C calling C#

Scenarios table

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>

Scenarios Detailed

These scenarios will use list<t> as the container in the examples

return list<T> @move

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

return list<T>

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?

Return collection with @move to C#

Return collection without @move from C to C#

Return collection with @move to C#

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment