csharp: Support argument marshalling in func ptrs

Function pointers now go through the same argument marshalling pipeline
as normal functions.

This will enable interfaces like Efl.Ui.Format to work properly.
This commit is contained in:
Lauro Moura 2018-03-21 22:39:17 -03:00 committed by Felipe Magno de Almeida
parent 3fd1566a08
commit bffe42e71b
9 changed files with 99 additions and 19 deletions

View File

@ -429,6 +429,7 @@ TESTS += tests/efl_mono/mono_test_driver.sh
tests_efl_mono_efl_mono_SOURCES = \
tests/efl_mono/Main.cs \
tests/efl_mono/TestUtils.cs \
tests/efl_mono/BasicDirection.cs \
tests/efl_mono/Eina.cs \
tests/efl_mono/Eldbus.cs \
@ -437,11 +438,11 @@ tests_efl_mono_efl_mono_SOURCES = \
tests/efl_mono/Evas.cs \
tests/efl_mono/Events.cs \
tests/efl_mono/FunctionPointers.cs \
tests/efl_mono/FunctionPointerMarshalling.cs \
tests/efl_mono/Parts.cs \
tests/efl_mono/Strbuf.cs \
tests/efl_mono/Strings.cs \
tests/efl_mono/Structs.cs \
tests/efl_mono/TestUtils.cs \
tests/efl_mono/Value.cs \
tests/efl_mono/ValueEolian.cs

View File

@ -27,7 +27,6 @@ inline bool is_function_blacklisted(std::string const& c_name)
|| c_name == "efl_ui_focus_user_parent_get"
|| c_name == "efl_canvas_object_scale_get" // duplicated signature
|| c_name == "efl_canvas_object_scale_set" // duplicated signature
|| c_name == "efl_ui_format_cb_set"
|| c_name == "efl_access_parent_get"
|| c_name == "efl_access_name_get"
|| c_name == "efl_access_name_set"

View File

@ -10,13 +10,7 @@
#include "grammar/list.hpp"
#include "grammar/alternative.hpp"
#include "grammar/attribute_reorder.hpp"
/* #include "type.hh" */
/* #include "marshall_type.hh" */
#include "parameter.hh"
#include "function_pointer.hh"
/* #include "keyword.hh" */
/* #include "using_decl.hh" */
/* #include "generation_contexts.hh" */
namespace eolian_mono {
@ -164,6 +158,10 @@ struct native_function_definition_epilogue_parameterized
{
return {&klass};
}
native_function_definition_epilogue_generator const operator()(attributes::klass_def const* klass=nullptr) const
{
return {klass};
}
} const native_function_definition_epilogue;
struct function_definition_epilogue_terminal

View File

@ -6,7 +6,9 @@
#include <vector>
#include <string>
#include "function_helpers.hh"
#include "documentation.hh"
#include "generation_contexts.hh"
namespace eolian_mono {
@ -21,7 +23,7 @@ static bool is_function_ptr_blacklisted(attributes::function_def const& func, st
std::string name = full_name.str();
return name == "Efl.Ui.Format_Func_Cb";
return false;
}
struct function_pointer {
@ -30,23 +32,29 @@ struct function_pointer {
{
// FIXME export Typedecl in eolian_cxx API
std::vector<std::string> namespaces = escape_namespace(namesp);
auto funcptr_ctx = context_add_tag(class_context{class_context::function_ptr}, context);
std::string return_type;
if(!as_generator(eolian_mono::type(true)).generate(std::back_inserter(return_type), f.return_type, context))
return false;
if (is_function_ptr_blacklisted(f, namesp))
return true;
auto open_namespace = *("namespace " << string << " {") << "\n";
if(!as_generator(open_namespace).generate(sink, namespaces, add_lower_case_context(context))) return false;
if(!as_generator(open_namespace).generate(sink, namespaces, add_lower_case_context(funcptr_ctx))) return false;
// C# visible delegate
if (!as_generator(documentation
<< "public delegate " << type << " " << string
<< "(" << (parameter % ", ") << ");\n")
.generate(sink, std::make_tuple(f, f.return_type, escape_keyword(f.name), f.parameters), context))
.generate(sink, std::make_tuple(f, f.return_type, escape_keyword(f.name), f.parameters), funcptr_ctx))
return false;
// "Internal" delegate, 1-to-1 with the Unamaged function type
if (!as_generator("internal delegate " << type << " " << string // public?
<< "Internal(IntPtr data, " << (parameter % ", ") << ");\n")
.generate(sink, std::make_tuple(f.return_type, escape_keyword(f.name), f.parameters), context))
if (!as_generator(marshall_native_annotation(true)
<< "internal delegate " << marshall_type(true) << " " << string // public?
<< "Internal(IntPtr data" << *grammar::attribute_reorder<-1, -1>((", " << marshall_native_annotation << " " << marshall_parameter)) << ");\n")
.generate(sink, std::make_tuple(f.return_type, f.return_type, escape_keyword(f.name), f.parameters), funcptr_ctx))
return false;
std::string f_name = escape_keyword(f.name);
@ -72,21 +80,31 @@ struct function_pointer {
<< scope_tab << "internal " << type << " ManagedCb(" << (parameter % ",") << ")\n"
<< scope_tab << "{\n"
<< scope_tab << scope_tab << (f.return_type.c_type != "void" ? "return ": "") << "_cb(_cb_data, " << (argument_invocation_no_conversion % ", ") << ");\n"
<< function_definition_preamble << "_cb(_cb_data, " << (argument_invocation % ", ") << ");\n"
<< function_definition_epilogue
<< scope_tab << "}\n\n"
<< scope_tab << "internal static " << type << " Cb(IntPtr cb_data, " << (parameter % ", ") << ")\n"
<< scope_tab << marshall_native_annotation(true)
<< scope_tab << "internal static " << marshall_type(true) << " Cb(IntPtr cb_data" << *grammar::attribute_reorder<-1, -1>((", " << marshall_native_annotation << " " << marshall_parameter)) << ")\n"
<< scope_tab << "{\n"
<< scope_tab << scope_tab << "GCHandle handle = GCHandle.FromIntPtr(cb_data);\n"
<< scope_tab << scope_tab << string << " cb = (" << string << ")handle.Target;\n"
<< scope_tab << scope_tab << (f.return_type.c_type != "void" ? "return " : "") << "cb(" << (argument_invocation_no_conversion % ", ") << ");\n"
<< native_function_definition_preamble
<< scope_tab << scope_tab << "try {\n"
<< scope_tab << scope_tab << scope_tab << (return_type != " void" ? "_ret_var = " : "") << "cb(" << (native_argument_invocation % ", ") << ");\n"
<< scope_tab << scope_tab << "} catch (Exception e) {\n"
<< scope_tab << scope_tab << scope_tab << "eina.Log.Warning($\"Callback error: {e.ToString()}\");\n"
<< scope_tab << scope_tab << scope_tab << "eina.Error.Set(eina.Error.EFL_ERROR);\n"
<< scope_tab << scope_tab << "}\n"
<< native_function_definition_epilogue(nullptr)
<< scope_tab << "}\n"
<< "}\n"
).generate(sink, std::make_tuple(f.return_type, f.parameters, f.parameters, f.return_type, f.parameters, f_name, f_name, f.parameters), context))
).generate(sink, std::make_tuple(f.return_type, f.parameters, f, f.parameters, f, f.return_type, f.return_type, f.parameters, f_name, f_name, f, f.parameters, f), funcptr_ctx))
return false;
auto close_namespace = *(lit("} ")) << "\n";
if(!as_generator(close_namespace).generate(sink, namespaces, context)) return false;
if(!as_generator(close_namespace).generate(sink, namespaces, funcptr_ctx)) return false;
return true;
}

View File

@ -11,6 +11,7 @@ struct class_context
inherit,
inherit_native,
structs,
function_ptr,
};
wrapper_kind current_wrapper_kind;
};

View File

@ -15,6 +15,16 @@ public class Example
return button;
}
public static void Formatter(eina.Strbuf buf, eina.Value val){
double ratio;
if (val.Get(out ratio)) {
buf.Append($"{(int)(ratio*100)}%");
} else {
buf.Append("Error");
}
}
#if WIN32 // Passed to the C# compiler with -define:WIN32
// Mono on Windows by default uses multi-thread apartments for COM stuff while
// OLE - used by ecore win32 DnD requires single threading for COM.
@ -41,6 +51,7 @@ public class Example
efl.ui.Progressbar bar = new efl.ui.ProgressbarConcrete(box);
bar.SetSize(new eina.Size2D(W, H));
bar.SetFormatCb(Formatter);
efl.ui.Slider slider = new efl.ui.SliderConcrete(box);
slider.SetSize(new eina.Size2D(W, H));

View File

@ -0,0 +1,31 @@
using System;
using System.Linq;
using System.Runtime.InteropServices;
namespace TestSuite
{
class TestFunctionPointerMarshalling
{
public static void func_pointer_marshalling()
{
test.Testing obj = new test.TestingConcrete();
bool called = false;
eina.Strbuf buf = new eina.Strbuf();
string argument = "Some String";
eina.Value v = new eina.Value(eina.ValueType.String);
v.Set(argument);
string reference = new string(argument.ToCharArray().Reverse().ToArray());
obj.CallFormatCb(buf, v, (eina.Strbuf ibuf, eina.Value val) => {
called = true;
string str = null;
val.Get(out str);
buf.Append(new string(str.ToCharArray().Reverse().ToArray()));
});
Test.Assert(called, "Callback was not called");
Test.AssertEquals(reference, buf.Steal());
}
}
}

View File

@ -3756,6 +3756,13 @@ void _test_testing_call_append_to_strbuf(Eo * obj, EINA_UNUSED Test_Testing_Data
test_testing_append_to_strbuf(obj, buf, str);
}
void _test_testing_call_format_cb(EINA_UNUSED Eo *obj, EINA_UNUSED Test_Testing_Data *pd, Eina_Strbuf *buf, const Eina_Value value,
void *func_data, Test_FormatCb func, Eina_Free_Cb func_free_cb)
{
func(func_data, buf, value);
func_free_cb(func_data);
}
#include "test_testing.eo.c"
#include "test_numberwrapper.eo.c"

View File

@ -81,6 +81,13 @@ function Test.SimpleCb {
return: int;
};
function Test.FormatCb {
params {
@in str: strbuf;
@in value: const(any_value);
}
};
class Test.Testing (Efl.Object, Efl.Part) {
parts {
@ -1569,6 +1576,13 @@ class Test.Testing (Efl.Object, Efl.Part) {
}
}
call_format_cb {
params {
@in str: strbuf;
@in value: const(any_value);
@in func: Test.FormatCb;
}
}
}
implements {
class.constructor;