csharp: Update string marshalers

Mostly done, needs work on strings being returned without ownership from
C# to C.
This commit is contained in:
Lauro Moura 2019-12-06 19:25:14 -03:00
parent 52da69510f
commit c1293edbd2
5 changed files with 127 additions and 24 deletions

View File

@ -51,23 +51,22 @@ struct marshall_annotation_visitor_generate
eina::optional<bool> has_own; eina::optional<bool> has_own;
std::function<std::string()> function; std::function<std::string()> function;
}; };
// These two tables are currently the same but will hold different marshallers
// for @in and @out/return semantics in a future commit. match const input_match_table[] =
match const parameter_match_table[] =
{ {
// signed primitives // signed primitives
{"bool", nullptr, [] { return "MarshalAs(UnmanagedType.U1)"; }}, {"bool", nullptr, [] { return "MarshalAs(UnmanagedType.U1)"; }},
{"string", true, [] { {"string", true, [] {
return "MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(Efl.Eo.StringPassOwnershipMarshaler))"; return "MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(Efl.Eo.StringInPassOwnershipMarshaler))";
}}, }},
{"string", false, [] { {"string", false, [] {
return "MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(Efl.Eo.StringKeepOwnershipMarshaler))"; return "MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(Efl.Eo.StringInKeepOwnershipMarshaler))";
}}, }},
{"mstring", true, [] { {"mstring", true, [] {
return "MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(Efl.Eo.StringPassOwnershipMarshaler))"; return "MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(Efl.Eo.StringInPassOwnershipMarshaler))";
}}, }},
{"mstring", false, [] { {"mstring", false, [] {
return "MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(Efl.Eo.StringKeepOwnershipMarshaler))"; return "MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(Efl.Eo.StringInKeepOwnershipMarshaler))";
}}, }},
{"stringshare", true, [] { {"stringshare", true, [] {
return "MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(Efl.Eo.StringsharePassOwnershipMarshaler))"; return "MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(Efl.Eo.StringsharePassOwnershipMarshaler))";
@ -96,16 +95,16 @@ struct marshall_annotation_visitor_generate
// signed primitives // signed primitives
{"bool", nullptr, [] { return "MarshalAs(UnmanagedType.U1)"; }}, {"bool", nullptr, [] { return "MarshalAs(UnmanagedType.U1)"; }},
{"string", true, [] { {"string", true, [] {
return "MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(Efl.Eo.StringPassOwnershipMarshaler))"; return "MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(Efl.Eo.StringOutPassOwnershipMarshaler))";
}}, }},
{"string", false, [] { {"string", false, [] {
return "MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(Efl.Eo.StringKeepOwnershipMarshaler))"; return "MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(Efl.Eo.StringOutKeepOwnershipMarshaler))";
}}, }},
{"mstring", true, [] { {"mstring", true, [] {
return "MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(Efl.Eo.StringPassOwnershipMarshaler))"; return "MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(Efl.Eo.StringOutPassOwnershipMarshaler))";
}}, }},
{"mstring", false, [] { {"mstring", false, [] {
return "MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(Efl.Eo.StringKeepOwnershipMarshaler))"; return "MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(Efl.Eo.StringOutKeepOwnershipMarshaler))";
}}, }},
{"stringshare", true, [] { {"stringshare", true, [] {
return "MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(Efl.Eo.StringsharePassOwnershipMarshaler))"; return "MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(Efl.Eo.StringsharePassOwnershipMarshaler))";
@ -143,7 +142,7 @@ struct marshall_annotation_visitor_generate
return as_generator("[" << prefix << marshalTag << "]").generate(sink, nullptr, *context); return as_generator("[" << prefix << marshalTag << "]").generate(sink, nullptr, *context);
}; };
const auto& match_table = is_return ? return_match_table : parameter_match_table; const auto& match_table = (is_return || is_out) ? return_match_table : input_match_table;
if(eina::optional<bool> b = type_match::get_match(match_table, predicate, acceptCb)) if(eina::optional<bool> b = type_match::get_match(match_table, predicate, acceptCb))
{ {

View File

@ -43,7 +43,7 @@ internal static class Environment
internal static partial class NativeCustomExportFunctions internal static partial class NativeCustomExportFunctions
{ {
[DllImport(efl.Libs.CustomExports, CharSet=CharSet.Ansi)] [DllImport(efl.Libs.CustomExports, CharSet=CharSet.Ansi)]
[return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(Efl.Eo.StringKeepOwnershipMarshaler))] [return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(Efl.Eo.StringOutKeepOwnershipMarshaler))]
public static extern string efl_mono_native_getenv(string name); public static extern string efl_mono_native_getenv(string name);
[DllImport(efl.Libs.CustomExports, CharSet=CharSet.Ansi)] [DllImport(efl.Libs.CustomExports, CharSet=CharSet.Ansi)]

View File

@ -51,13 +51,13 @@ static internal class StrbufNativeMethods
[DllImport(efl.Libs.Eina, CharSet=CharSet.Ansi)] [DllImport(efl.Libs.Eina, CharSet=CharSet.Ansi)]
[return: [return:
MarshalAs(UnmanagedType.CustomMarshaler, MarshalAs(UnmanagedType.CustomMarshaler,
MarshalTypeRef=typeof(Efl.Eo.StringPassOwnershipMarshaler))] MarshalTypeRef=typeof(Efl.Eo.StringOutPassOwnershipMarshaler))]
internal static extern string eina_strbuf_string_steal(IntPtr buf); internal static extern string eina_strbuf_string_steal(IntPtr buf);
[DllImport(efl.Libs.Eina, CharSet=CharSet.Ansi)] [DllImport(efl.Libs.Eina, CharSet=CharSet.Ansi)]
[return: [return:
MarshalAs(UnmanagedType.CustomMarshaler, MarshalAs(UnmanagedType.CustomMarshaler,
MarshalTypeRef=typeof(Efl.Eo.StringKeepOwnershipMarshaler))] MarshalTypeRef=typeof(Efl.Eo.StringOutKeepOwnershipMarshaler))]
internal static extern string eina_strbuf_string_get(IntPtr buf); internal static extern string eina_strbuf_string_get(IntPtr buf);
[DllImport(efl.Libs.Eina)] [DllImport(efl.Libs.Eina)]

View File

@ -194,7 +194,7 @@ static internal class UnsafeNativeMethods
[DllImport(efl.Libs.Eina, CharSet=CharSet.Ansi)] [DllImport(efl.Libs.Eina, CharSet=CharSet.Ansi)]
[return: [return:
MarshalAs(UnmanagedType.CustomMarshaler, MarshalAs(UnmanagedType.CustomMarshaler,
MarshalTypeRef=typeof(Efl.Eo.StringPassOwnershipMarshaler))] MarshalTypeRef=typeof(Efl.Eo.StringOutPassOwnershipMarshaler))]
internal static extern string eina_value_to_string(IntPtr handle); // We take ownership of the returned string. internal static extern string eina_value_to_string(IntPtr handle); // We take ownership of the returned string.
[DllImport(efl.Libs.CustomExports)] [DllImport(efl.Libs.CustomExports)]

View File

@ -5,8 +5,12 @@ namespace Efl
{ {
namespace Eo namespace Eo
{ {
class StringPassOwnershipMarshaler : ICustomMarshaler /// <summary>
/// Marshaler for <c>@in</c> parameters that have their ownership transfered.
/// </summary>
class StringInPassOwnershipMarshaler : ICustomMarshaler
{ {
// Called when C calls a C# method passing data to it
public object MarshalNativeToManaged(IntPtr pNativeData) public object MarshalNativeToManaged(IntPtr pNativeData)
{ {
var ret = Eina.StringConversion.NativeUtf8ToManagedString(pNativeData); var ret = Eina.StringConversion.NativeUtf8ToManagedString(pNativeData);
@ -14,16 +18,18 @@ namespace Efl
return ret; return ret;
} }
// Called when C# calls a C method passing data to it
public IntPtr MarshalManagedToNative(object managedObj) public IntPtr MarshalManagedToNative(object managedObj)
{ {
return Eina.MemoryNative.StrDup((string)managedObj); return Eina.MemoryNative.StrDup((string)managedObj);
} }
// Called when the C call returns, cleaning the result from MarshalManagedToNative
public void CleanUpNativeData(IntPtr pNativeData) public void CleanUpNativeData(IntPtr pNativeData)
{ {
// No need to cleanup. C will take care of it.
} }
// Called when the C# call returns, cleaning the result from MarshalNativeToManaged
public void CleanUpManagedData(object managedObj) public void CleanUpManagedData(object managedObj)
{ {
} }
@ -37,32 +43,86 @@ namespace Efl
{ {
if (marshaler == null) if (marshaler == null)
{ {
marshaler = new StringPassOwnershipMarshaler(); marshaler = new StringInPassOwnershipMarshaler();
} }
return marshaler; return marshaler;
} }
static private StringPassOwnershipMarshaler marshaler; static private ICustomMarshaler marshaler;
} }
class StringKeepOwnershipMarshaler: ICustomMarshaler /// <summary>
/// Marshaler for <c>@in</c> parameters that do not change their ownership.
/// </summary>
class StringInKeepOwnershipMarshaler: ICustomMarshaler
{ {
// Called when C calls a C# method passing data to it
public object MarshalNativeToManaged(IntPtr pNativeData) public object MarshalNativeToManaged(IntPtr pNativeData)
{ {
return Eina.StringConversion.NativeUtf8ToManagedString(pNativeData); return Eina.StringConversion.NativeUtf8ToManagedString(pNativeData);
} }
// Called when C# calls a C method passing data to it
public IntPtr MarshalManagedToNative(object managedObj) public IntPtr MarshalManagedToNative(object managedObj)
{ {
return Eina.StringConversion.ManagedStringToNativeUtf8Alloc((string)managedObj); return Eina.StringConversion.ManagedStringToNativeUtf8Alloc((string)managedObj);
} }
// Called when the C call returns, cleaning the result from MarshalManagedToNative
public void CleanUpNativeData(IntPtr pNativeData) public void CleanUpNativeData(IntPtr pNativeData)
{ {
// No need to free. The Native side will keep the ownership. Eina.MemoryNative.Free(pNativeData);
} }
// Called when the C# call returns, cleaning the result from MarshalNativeToManaged
public void CleanUpManagedData(object managedObj)
{
// GC will should take care of it.
}
public int GetNativeDataSize()
{
return -1;
}
internal static ICustomMarshaler GetInstance(string cookie)
{
if (marshaler == null)
{
marshaler = new StringInKeepOwnershipMarshaler();
}
return marshaler;
}
static private ICustomMarshaler marshaler;
}
class StringOutPassOwnershipMarshaler : ICustomMarshaler
{
// Called when C# calls a C method and receives data from it
public object MarshalNativeToManaged(IntPtr pNativeData)
{
var ret = Eina.StringConversion.NativeUtf8ToManagedString(pNativeData);
// C gave us ownership. Let's free.
Eina.MemoryNative.Free(pNativeData);
return ret;
}
// Called when C calls a C# method and receives data from it
public IntPtr MarshalManagedToNative(object managedObj)
{
// As we're passing up the ownership, no need to free it.
return Eina.MemoryNative.StrDup((string)managedObj);
}
// Called when the C call returns, cleaning the result it gave to C#
public void CleanUpNativeData(IntPtr pNativeData)
{
}
// Called when the C# call returns, cleaning the result it gave to C.
public void CleanUpManagedData(object managedObj) public void CleanUpManagedData(object managedObj)
{ {
} }
@ -76,13 +136,57 @@ namespace Efl
{ {
if (marshaler == null) if (marshaler == null)
{ {
marshaler = new StringKeepOwnershipMarshaler(); marshaler = new StringOutPassOwnershipMarshaler();
} }
return marshaler; return marshaler;
} }
static private StringKeepOwnershipMarshaler marshaler; static private ICustomMarshaler marshaler;
}
class StringOutKeepOwnershipMarshaler: ICustomMarshaler
{
// Called when C# calls a C method and receives data from it
public object MarshalNativeToManaged(IntPtr pNativeData)
{
return Eina.StringConversion.NativeUtf8ToManagedString(pNativeData);
}
// Called when C calls a C# method and receives data from it
public IntPtr MarshalManagedToNative(object managedObj)
{
// FIXME This will be the tricky one, as it can leak.
return Eina.StringConversion.ManagedStringToNativeUtf8Alloc((string)managedObj);
}
// Called when the C call returns, cleaning the result it gave to C#
public void CleanUpNativeData(IntPtr pNativeData)
{
// No need to free. The Native side will keep the ownership.
}
// Called when the C call returns, cleaning the result it gave to C#
public void CleanUpManagedData(object managedObj)
{
}
public int GetNativeDataSize()
{
return -1;
}
internal static ICustomMarshaler GetInstance(string cookie)
{
if (marshaler == null)
{
marshaler = new StringOutKeepOwnershipMarshaler();
}
return marshaler;
}
static private ICustomMarshaler marshaler;
} }
} }