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;
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 parameter_match_table[] =
match const input_match_table[] =
{
// signed primitives
{"bool", nullptr, [] { return "MarshalAs(UnmanagedType.U1)"; }},
{"string", true, [] {
return "MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(Efl.Eo.StringPassOwnershipMarshaler))";
return "MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(Efl.Eo.StringInPassOwnershipMarshaler))";
}},
{"string", false, [] {
return "MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(Efl.Eo.StringKeepOwnershipMarshaler))";
return "MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(Efl.Eo.StringInKeepOwnershipMarshaler))";
}},
{"mstring", true, [] {
return "MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(Efl.Eo.StringPassOwnershipMarshaler))";
return "MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(Efl.Eo.StringInPassOwnershipMarshaler))";
}},
{"mstring", false, [] {
return "MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(Efl.Eo.StringKeepOwnershipMarshaler))";
return "MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(Efl.Eo.StringInKeepOwnershipMarshaler))";
}},
{"stringshare", true, [] {
return "MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(Efl.Eo.StringsharePassOwnershipMarshaler))";
@ -96,16 +95,16 @@ struct marshall_annotation_visitor_generate
// signed primitives
{"bool", nullptr, [] { return "MarshalAs(UnmanagedType.U1)"; }},
{"string", true, [] {
return "MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(Efl.Eo.StringPassOwnershipMarshaler))";
return "MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(Efl.Eo.StringOutPassOwnershipMarshaler))";
}},
{"string", false, [] {
return "MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(Efl.Eo.StringKeepOwnershipMarshaler))";
return "MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(Efl.Eo.StringOutKeepOwnershipMarshaler))";
}},
{"mstring", true, [] {
return "MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(Efl.Eo.StringPassOwnershipMarshaler))";
return "MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(Efl.Eo.StringOutPassOwnershipMarshaler))";
}},
{"mstring", false, [] {
return "MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(Efl.Eo.StringKeepOwnershipMarshaler))";
return "MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(Efl.Eo.StringOutKeepOwnershipMarshaler))";
}},
{"stringshare", true, [] {
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);
};
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))
{

View File

@ -43,7 +43,7 @@ internal static class Environment
internal static partial class NativeCustomExportFunctions
{
[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);
[DllImport(efl.Libs.CustomExports, CharSet=CharSet.Ansi)]

View File

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

View File

@ -194,7 +194,7 @@ static internal class UnsafeNativeMethods
[DllImport(efl.Libs.Eina, CharSet=CharSet.Ansi)]
[return:
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.
[DllImport(efl.Libs.CustomExports)]

View File

@ -5,8 +5,12 @@ namespace Efl
{
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)
{
var ret = Eina.StringConversion.NativeUtf8ToManagedString(pNativeData);
@ -14,16 +18,18 @@ namespace Efl
return ret;
}
// Called when C# calls a C method passing data to it
public IntPtr MarshalManagedToNative(object managedObj)
{
return Eina.MemoryNative.StrDup((string)managedObj);
}
// Called when the C call returns, cleaning the result from MarshalManagedToNative
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)
{
}
@ -37,32 +43,86 @@ namespace Efl
{
if (marshaler == null)
{
marshaler = new StringPassOwnershipMarshaler();
marshaler = new StringInPassOwnershipMarshaler();
}
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)
{
return Eina.StringConversion.NativeUtf8ToManagedString(pNativeData);
}
// Called when C# calls a C method passing data to it
public IntPtr MarshalManagedToNative(object managedObj)
{
return Eina.StringConversion.ManagedStringToNativeUtf8Alloc((string)managedObj);
}
// Called when the C call returns, cleaning the result from MarshalManagedToNative
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)
{
}
@ -76,13 +136,57 @@ namespace Efl
{
if (marshaler == null)
{
marshaler = new StringKeepOwnershipMarshaler();
marshaler = new StringOutPassOwnershipMarshaler();
}
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;
}
}