felipealmeida pushed a commit to branch master. http://git.enlightenment.org/core/efl.git/commit/?id=bffe42e71ba12292d4969bba729e67ddf03cc111
commit bffe42e71ba12292d4969bba729e67ddf03cc111 Author: Lauro Moura <[email protected]> Date: Wed Mar 21 22:39:17 2018 -0300 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. --- src/Makefile_Efl_Mono.am | 3 +- .../eolian_mono/eolian/mono/function_blacklist.hh | 1 - .../eolian_mono/eolian/mono/function_helpers.hh | 10 +++--- .../eolian_mono/eolian/mono/function_pointer.hh | 40 ++++++++++++++++------ .../eolian_mono/eolian/mono/generation_contexts.hh | 1 + src/examples/elementary/efl_ui_slider_mono.cs | 11 ++++++ src/tests/efl_mono/FunctionPointerMarshalling.cs | 31 +++++++++++++++++ src/tests/efl_mono/libefl_mono_native_test.c | 7 ++++ src/tests/efl_mono/test_testing.eo | 14 ++++++++ 9 files changed, 99 insertions(+), 19 deletions(-) diff --git a/src/Makefile_Efl_Mono.am b/src/Makefile_Efl_Mono.am index beb287ce3f..45928f977a 100644 --- a/src/Makefile_Efl_Mono.am +++ b/src/Makefile_Efl_Mono.am @@ -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 diff --git a/src/bin/eolian_mono/eolian/mono/function_blacklist.hh b/src/bin/eolian_mono/eolian/mono/function_blacklist.hh index b2d712c6ac..f3ec3011d5 100644 --- a/src/bin/eolian_mono/eolian/mono/function_blacklist.hh +++ b/src/bin/eolian_mono/eolian/mono/function_blacklist.hh @@ -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" diff --git a/src/bin/eolian_mono/eolian/mono/function_helpers.hh b/src/bin/eolian_mono/eolian/mono/function_helpers.hh index 2b8c912d44..acfe850032 100644 --- a/src/bin/eolian_mono/eolian/mono/function_helpers.hh +++ b/src/bin/eolian_mono/eolian/mono/function_helpers.hh @@ -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 diff --git a/src/bin/eolian_mono/eolian/mono/function_pointer.hh b/src/bin/eolian_mono/eolian/mono/function_pointer.hh index 0890edcb51..2c0c193c33 100644 --- a/src/bin/eolian_mono/eolian/mono/function_pointer.hh +++ b/src/bin/eolian_mono/eolian/mono/function_pointer.hh @@ -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; } diff --git a/src/bin/eolian_mono/eolian/mono/generation_contexts.hh b/src/bin/eolian_mono/eolian/mono/generation_contexts.hh index 8563afcb12..d7e31ddae2 100644 --- a/src/bin/eolian_mono/eolian/mono/generation_contexts.hh +++ b/src/bin/eolian_mono/eolian/mono/generation_contexts.hh @@ -11,6 +11,7 @@ struct class_context inherit, inherit_native, structs, + function_ptr, }; wrapper_kind current_wrapper_kind; }; diff --git a/src/examples/elementary/efl_ui_slider_mono.cs b/src/examples/elementary/efl_ui_slider_mono.cs index d458104cc9..64c31ab921 100644 --- a/src/examples/elementary/efl_ui_slider_mono.cs +++ b/src/examples/elementary/efl_ui_slider_mono.cs @@ -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)); diff --git a/src/tests/efl_mono/FunctionPointerMarshalling.cs b/src/tests/efl_mono/FunctionPointerMarshalling.cs new file mode 100644 index 0000000000..e7627a87f1 --- /dev/null +++ b/src/tests/efl_mono/FunctionPointerMarshalling.cs @@ -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()); + } +} +} diff --git a/src/tests/efl_mono/libefl_mono_native_test.c b/src/tests/efl_mono/libefl_mono_native_test.c index f16c8957c3..fff2173ae8 100644 --- a/src/tests/efl_mono/libefl_mono_native_test.c +++ b/src/tests/efl_mono/libefl_mono_native_test.c @@ -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" diff --git a/src/tests/efl_mono/test_testing.eo b/src/tests/efl_mono/test_testing.eo index 5d1e7aa503..9a9aa0f2d1 100644 --- a/src/tests/efl_mono/test_testing.eo +++ b/src/tests/efl_mono/test_testing.eo @@ -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; --
