diff --git a/src/Makefile_Efl_Mono.am b/src/Makefile_Efl_Mono.am index e442d09fb5..1f718ecc28 100644 --- a/src/Makefile_Efl_Mono.am +++ b/src/Makefile_Efl_Mono.am @@ -419,6 +419,7 @@ TESTS += tests/efl_mono/mono_test_driver.sh tests_efl_mono_efl_mono_SOURCES = \ tests/efl_mono/Main.cs \ + tests/efl_mono/BasicDirection.cs \ tests/efl_mono/Eina.cs \ tests/efl_mono/Eldbus.cs \ tests/efl_mono/Eo.cs \ diff --git a/src/bin/eolian_mono/eolian/mono/function_helpers.hh b/src/bin/eolian_mono/eolian/mono/function_helpers.hh index e7af6f9dc0..2b8c912d44 100644 --- a/src/bin/eolian_mono/eolian/mono/function_helpers.hh +++ b/src/bin/eolian_mono/eolian/mono/function_helpers.hh @@ -98,9 +98,11 @@ struct native_function_definition_epilogue_generator if (!as_generator( scope_tab << scope_tab << "//Assigning out variables\n" << *(scope_tab << scope_tab << native_convert_out_assign(*klass) << "\n") + << scope_tab << scope_tab << "//Placeholder in ptr variables that need to be updated\n" + << *(scope_tab << scope_tab << native_convert_in_ptr_assign << "\n") << scope_tab << scope_tab << "//Converting return variable\n" << scope_tab << scope_tab << native_convert_return(*klass) - ).generate(sink, std::make_tuple(f.parameters, f.return_type), context)) + ).generate(sink, std::make_tuple(f.parameters, f.parameters, f.return_type), context)) return false; return true; @@ -117,9 +119,11 @@ struct function_definition_epilogue_generator scope_tab << scope_tab << "eina.Error.RaiseIfOccurred();\n" << scope_tab << scope_tab << "//Assigning out variables\n" << *(scope_tab << scope_tab << convert_out_assign << "\n") + << scope_tab << scope_tab << "//Placeholder in ptr variables that need to be updated\n" + << *(scope_tab << scope_tab << convert_in_ptr_assign << "\n") << scope_tab << scope_tab << "//Converting return variable\n" << scope_tab << scope_tab << convert_return - ).generate(sink, std::make_tuple(f.parameters, f.return_type), context)) + ).generate(sink, std::make_tuple(f.parameters, f.parameters, f.return_type), context)) return false; return true; diff --git a/src/bin/eolian_mono/eolian/mono/helpers.hh b/src/bin/eolian_mono/eolian/mono/helpers.hh index e02fd05b70..d1bebeee14 100644 --- a/src/bin/eolian_mono/eolian/mono/helpers.hh +++ b/src/bin/eolian_mono/eolian/mono/helpers.hh @@ -53,6 +53,30 @@ inline bool need_struct_conversion(attributes::regular_type_def const* regular) return regular && regular->is_struct() && !is_struct_blacklisted(*regular); } +inline bool need_struct_conversion(attributes::parameter_def const& param, attributes::regular_type_def const* regular) +{ + if (param.direction == attributes::parameter_direction::in && param.type.has_own) + return false; + + return need_struct_conversion(regular); +} + +inline bool need_struct_conversion_in_return(attributes::type_def const& ret_type, attributes::parameter_direction const& direction) +{ + auto regular = efl::eina::get(&ret_type.original_type); + + if (!regular->is_struct()) + return false; + + if (regular->is_struct() && (direction == attributes::parameter_direction::out || direction == attributes::parameter_direction::unknown)) + return false; + + if (ret_type.has_own) + return false; + + return true; +} + inline bool need_pointer_conversion(attributes::regular_type_def const* regular) { if (!regular) diff --git a/src/bin/eolian_mono/eolian/mono/marshall_type.hh b/src/bin/eolian_mono/eolian/mono/marshall_type.hh index a946e15ea8..79ce8b6380 100644 --- a/src/bin/eolian_mono/eolian/mono/marshall_type.hh +++ b/src/bin/eolian_mono/eolian/mono/marshall_type.hh @@ -16,6 +16,16 @@ struct marshall_annotation_visitor_generate; template struct marshall_native_annotation_visitor_generate; } + +/* + * Converts a given type/parameter to the type used in the DllImport signatures. + * + * For example, Eina.Value can be marshaled either as an eina.Value instance through + * CustomMarshallers if we have a ptr(Eina.Value) or through the intermediate + * eina.Value_Native blittable struct if it is passed by value. + * + * For details, check marshall_type_impl.h with the actual conversion rules. + */ struct marshall_type_generator { marshall_type_generator(bool is_return = false) @@ -26,6 +36,7 @@ struct marshall_type_generator { return type.original_type.visit(detail::marshall_type_visitor_generate{sink, &context, type.c_type, false, is_return, type.is_ptr }); } + /* Some types may require a different conversion when they are in @out parameters. */ template bool generate(OutputIterator sink, attributes::parameter_def const& param, Context const& context) const { @@ -36,6 +47,12 @@ struct marshall_type_generator bool is_return; }; +/* + * Generates the "[MarshalAs(...)]" rules for the given type. + * + * For example, the CustomMarshallers definitions for String and eina.Values and the + * boolean size defintion (Eina_Value is 1 byte, while C# bool has 4 bytes). + */ struct marshall_annotation_generator { marshall_annotation_generator(bool is_return = false) diff --git a/src/bin/eolian_mono/eolian/mono/marshall_type_impl.hh b/src/bin/eolian_mono/eolian/mono/marshall_type_impl.hh index 89efc7f3e2..61a53745ca 100644 --- a/src/bin/eolian_mono/eolian/mono/marshall_type_impl.hh +++ b/src/bin/eolian_mono/eolian/mono/marshall_type_impl.hh @@ -149,8 +149,10 @@ struct marshall_type_visitor_generate }} }; - if (!is_ptr && regular.is_struct() && !is_struct_blacklisted(regular)) + if (regular.is_struct() && !is_struct_blacklisted(regular) && !(bool)(regular.base_qualifier & qualifier_info::is_own)) { + if ((is_out || is_return) && is_ptr) + return as_generator(" System.IntPtr").generate(sink, attributes::unused, *context); return as_generator(*(lower_case[string] << ".") << string << "_StructInternal") .generate(sink, std::make_tuple(eolian_mono::escape_namespace(regular.namespaces), regular.base_type), *context); } diff --git a/src/bin/eolian_mono/eolian/mono/parameter.hh b/src/bin/eolian_mono/eolian/mono/parameter.hh index d836124fe0..0487ee22b3 100644 --- a/src/bin/eolian_mono/eolian/mono/parameter.hh +++ b/src/bin/eolian_mono/eolian/mono/parameter.hh @@ -22,6 +22,8 @@ namespace eolian_mono { struct native_convert_out_variable_generator; struct convert_out_variable_generator; struct convert_out_assign_generator; + struct native_convert_in_ptr_assign_generator; + struct convert_in_ptr_assign_generator; struct native_convert_out_assign_parameterized; struct native_convert_out_assign_generator; struct convert_return_generator; @@ -135,6 +137,26 @@ template <> struct attributes_needed< ::eolian_mono::convert_out_assign_generator> : std::integral_constant {}; } +template <> +struct is_eager_generator< ::eolian_mono::native_convert_in_ptr_assign_generator> : std::true_type {}; +template <> +struct is_generator< ::eolian_mono::native_convert_in_ptr_assign_generator> : std::true_type {}; + +namespace type_traits { +template <> +struct attributes_needed< ::eolian_mono::native_convert_in_ptr_assign_generator> : std::integral_constant {}; +} + +template <> +struct is_eager_generator< ::eolian_mono::convert_in_ptr_assign_generator> : std::true_type {}; +template <> +struct is_generator< ::eolian_mono::convert_in_ptr_assign_generator> : std::true_type {}; + +namespace type_traits { +template <> +struct attributes_needed< ::eolian_mono::convert_in_ptr_assign_generator> : std::integral_constant {}; +} + template <> struct is_eager_generator< ::eolian_mono::convert_return_variable_generator> : std::true_type {}; template <> @@ -341,16 +363,31 @@ inline std::string direction_modifier(attributes::parameter_def const& param) } else if (param.direction != attributes::parameter_direction::in) { - auto regular = efl::eina::get(¶m.type.original_type); - if (param.type.c_type == "Eina_Slice" || param.type.c_type == "Eina_Rw_Slice" - || need_struct_conversion(regular)) + if (param.type.c_type == "Eina_Slice" || param.type.c_type == "Eina_Rw_Slice") return " ref "; else return " out "; } + else if (param.direction == attributes::parameter_direction::in && param.type.is_ptr) + { + auto regular = efl::eina::get(¶m.type.original_type); + if (need_struct_conversion(regular)) + return " ref "; // Don't add ref on Marshal if it is ptr + } return " "; } +std::string marshall_direction_modifier(attributes::parameter_def const& param) +{ + if (param.direction == attributes::parameter_direction::in && param.type.is_ptr) + { + auto regular = efl::eina::get(¶m.type.original_type); + if (need_struct_conversion(regular) && param.type.has_own) + return " "; // Don't add ref on Marshal if it is ptr + } + return direction_modifier(param); +} + struct is_fp_visitor { typedef is_fp_visitor visitor_type; @@ -412,7 +449,7 @@ struct marshall_parameter_generator if (!param.type.original_type.visit(is_fp_visitor{})) return as_generator( - direction_modifier(param) << marshall_type << " " << string + marshall_direction_modifier(param) << marshall_type << " " << string ).generate(sink, std::make_tuple(param, param_name), context); return as_generator( @@ -421,14 +458,15 @@ struct marshall_parameter_generator ).generate(sink, param, context); } } const marshall_parameter {}; - + +// FIXME This seems to be used only in the else branch of the native function definition. Is it really needed? struct argument_generator { template bool generate(OutputIterator sink, attributes::parameter_def const& param, Context const& context) const { std::string param_name = escape_keyword(param.param_name); - std::string direction = direction_modifier(param); + std::string direction = marshall_direction_modifier(param); if (!param.type.original_type.visit(is_fp_visitor{})) return as_generator( @@ -475,7 +513,7 @@ struct argument_invocation_generator template bool generate(OutputIterator sink, attributes::parameter_def const& param, Context const& context) const { - std::string arg = direction_modifier(param); + std::string arg = marshall_direction_modifier(param); if (use_conversion_vars && param_should_use_out_var(param, false)) arg += out_variable_name(param.param_name); @@ -507,7 +545,7 @@ struct native_convert_in_variable_generator return true; auto regular = efl::eina::get(¶m.type.original_type); - if (param.type.is_ptr && need_pointer_conversion(regular)) + if (param.type.is_ptr && need_pointer_conversion(regular) && !need_struct_conversion(param, regular)) { return as_generator( "var " << string << " = eina.PrimitiveConversion.PointerToManaged<" << type << ">(" << escape_keyword(param.param_name) << ");\n" @@ -575,7 +613,7 @@ struct convert_in_variable_generator return true; auto regular = efl::eina::get(¶m.type.original_type); - if (param.type.is_ptr && need_pointer_conversion(regular)) + if (param.type.is_ptr && need_pointer_conversion(regular) && !need_struct_conversion(param, regular)) { return as_generator( "var " << string << " = eina.PrimitiveConversion.ManagedToPointerAlloc(" << escape_keyword(param.param_name) << ");\n" @@ -659,7 +697,8 @@ struct convert_in_variable_generator } } const convert_in_variable {}; - + +/* Some types require an intermediate variable to be filled as out parameter in the marshalled function */ struct convert_out_variable_generator { template @@ -669,7 +708,7 @@ struct convert_out_variable_generator return true; auto regular = efl::eina::get(¶m.type.original_type); - if (param.type.is_ptr && need_pointer_conversion(regular)) + if (param.type.is_ptr && need_pointer_conversion(regular) && !need_struct_conversion(regular)) { return as_generator( "System.IntPtr " << string << " = System.IntPtr.Zero;\n" @@ -679,7 +718,7 @@ struct convert_out_variable_generator { return as_generator( "var " << string << " = new " << marshall_type << "();\n" - ).generate(sink, std::make_tuple(out_variable_name(param.param_name), param.type), context); + ).generate(sink, std::make_tuple(out_variable_name(param.param_name), param), context); } else if (param_is_acceptable(param, "Eina_Binbuf *", WANT_OWN, WANT_OUT) || param_is_acceptable(param, "Eina_Binbuf *", !WANT_OWN, WANT_OUT) @@ -742,7 +781,7 @@ struct native_convert_out_variable_generator return true; auto regular = efl::eina::get(¶m.type.original_type); - if (param.type.is_ptr && need_pointer_conversion(regular)) + if (param.type.is_ptr && need_pointer_conversion(regular) && !need_struct_conversion(regular)) { return as_generator( type << " " << string << " = default(" << type << ");\n" @@ -819,6 +858,7 @@ struct native_convert_out_variable_generator } const native_convert_out_variable {}; +/* Assign the Managed out variables from the marshalled intermediate ones if needed. */ struct convert_out_assign_generator { template @@ -828,11 +868,17 @@ struct convert_out_assign_generator return true; auto regular = efl::eina::get(¶m.type.original_type); - if (param.type.is_ptr && need_pointer_conversion(regular)) + if (param.type.is_ptr && need_pointer_conversion(regular) && !need_struct_conversion_in_return(param.type, param.direction)) { - return as_generator( + bool ret = as_generator( string << " = eina.PrimitiveConversion.PointerToManaged<" << type << ">(" << out_variable_name(param.param_name) << ");\n" ).generate(sink, std::make_tuple(escape_keyword(param.param_name), param.type), context); + + if (param.type.has_own) + ret = ret && as_generator(scope_tab << scope_tab << "Marshal.FreeHGlobal(" << out_variable_name(param.param_name) << ");\n" + ).generate(sink, attributes::unused, context); + + return ret; } else if (need_struct_conversion(regular)) { @@ -911,6 +957,40 @@ struct convert_out_assign_generator } const convert_out_assign {}; +struct native_convert_in_ptr_assign_generator +{ + template + bool generate(OutputIterator sink, attributes::parameter_def const& param, Context const& context) const + { + auto regular = efl::eina::get(¶m.type.original_type); + if (param_should_use_in_var(param, true) && param.type.is_ptr && !param.type.has_own && need_struct_conversion(regular)) + { + return as_generator( + string << " = " << type << "_StructConvertion.ToInternal(" << in_variable_name(param.param_name) << ");\n" + ).generate(sink, std::make_tuple(escape_keyword(param.param_name), param.type), context); + } + + return true; + } +} const native_convert_in_ptr_assign {}; + +struct convert_in_ptr_assign_generator +{ + template + bool generate(OutputIterator sink, attributes::parameter_def const& param, Context const& context) const + { + auto regular = efl::eina::get(¶m.type.original_type); + if (param_should_use_in_var(param, true) && param.type.is_ptr && !param.type.has_own && need_struct_conversion(regular)) + { + return as_generator( + string << " = " << type << "_StructConvertion.ToExternal(" << in_variable_name(param.param_name) << ");\n" + ).generate(sink, std::make_tuple(escape_keyword(param.param_name), param.type), context); + } + + return true; + } +} const convert_in_ptr_assign {}; + struct convert_return_variable_generator { template @@ -923,17 +1003,19 @@ struct convert_return_variable_generator } const convert_return_variable {}; - +/* Converts the intermediate return variable to the proper API type */ struct convert_return_generator { template bool generate(OutputIterator sink, attributes::type_def const& ret_type, Context const& context) const { auto regular = efl::eina::get(&ret_type.original_type); - if (ret_type.is_ptr && need_pointer_conversion(regular)) + if (ret_type.is_ptr && need_pointer_conversion(regular) && !need_struct_conversion_in_return(ret_type, attributes::parameter_direction::unknown)) { return as_generator( - "return eina.PrimitiveConversion.PointerToManaged<" << type << ">(_ret_var);\n" + "var __ret_tmp = eina.PrimitiveConversion.PointerToManaged<" << type << ">(_ret_var);\n" + << scope_tab << scope_tab << (ret_type.has_own ? ("Marshal.FreeHGlobal(_ret_var);\n"): "\n") + << scope_tab << scope_tab << "return __ret_tmp;\n" ).generate(sink, ret_type, context); } else if (need_struct_conversion(regular)) @@ -998,7 +1080,7 @@ struct native_convert_out_assign_generator return true; auto regular = efl::eina::get(¶m.type.original_type); - if (param.type.is_ptr && need_pointer_conversion(regular)) + if (param.type.is_ptr && need_pointer_conversion(regular) && !need_struct_conversion_in_return(param.type, param.direction)) { return as_generator( string << " = eina.PrimitiveConversion.ManagedToPointerAlloc(" << string << ");\n" @@ -1131,7 +1213,7 @@ struct native_convert_return_generator bool generate(OutputIterator sink, attributes::type_def const& ret_type, Context const& context) const { auto regular = efl::eina::get(&ret_type.original_type); - if (ret_type.is_ptr && need_pointer_conversion(regular)) + if (ret_type.is_ptr && need_pointer_conversion(regular) && !need_struct_conversion_in_return(ret_type, attributes::parameter_direction::unknown) ) { return as_generator( "return eina.PrimitiveConversion.ManagedToPointerAlloc(_ret_var);\n" diff --git a/src/bin/eolian_mono/eolian/mono/struct_definition.hh b/src/bin/eolian_mono/eolian/mono/struct_definition.hh index a0ff03315e..0b45da95b2 100644 --- a/src/bin/eolian_mono/eolian/mono/struct_definition.hh +++ b/src/bin/eolian_mono/eolian/mono/struct_definition.hh @@ -94,10 +94,11 @@ struct struct_internal_definition_generator { if (!as_generator ( + "///Internal wrapper for struct " << string << ".\n" "[StructLayout(LayoutKind.Sequential)]\n" - "internal struct " << string << "\n{\n" + "public struct " << string << "\n{\n" ) - .generate(sink, binding_struct_internal_name(struct_), context)) + .generate(sink, std::make_tuple<>(binding_struct_name(struct_), binding_struct_internal_name(struct_)), context)) return false; // iterate struct fields @@ -132,6 +133,24 @@ struct struct_internal_definition_generator return false; } + auto external_name = binding_struct_name(struct_); + auto internal_name = binding_struct_internal_name(struct_); + + if(!as_generator( + scope_tab << "///Implicit conversion to the internal/marshalling representation.\n" + << scope_tab << "public static implicit operator " << string << "(" << string << " struct_)\n" + << scope_tab << "{\n" + << scope_tab << scope_tab << "return " << string << "_StructConvertion.ToExternal(struct_);\n" + << scope_tab << "}\n" + << scope_tab << "///Implicit conversion to the managed representation.\n" + << scope_tab << "public static implicit operator " << string << "(" << string << " struct_)\n" + << scope_tab << "{\n" + << scope_tab << scope_tab << "return " << string << "_StructConvertion.ToInternal(struct_);\n" + << scope_tab << "}\n" + ).generate(sink, std::make_tuple(external_name, internal_name, external_name, + internal_name, external_name, external_name), context)) + return false; + if(!as_generator("}\n").generate(sink, attributes::unused, context)) return false; return true; @@ -172,7 +191,7 @@ struct to_internal_field_convert_generator .generate(sink, std::make_tuple(field_name, field_name), context)) return false; } - else if (field.type.is_ptr && need_pointer_conversion(regular)) + else if (field.type.is_ptr && need_pointer_conversion(regular) && !need_struct_conversion(regular)) { if (!as_generator( scope_tab << scope_tab << "_internal_struct." << string << " = eina.PrimitiveConversion.ManagedToPointerAlloc(_external_struct." << string << ");\n") @@ -282,7 +301,7 @@ struct to_external_field_convert_generator .generate(sink, std::make_tuple(field_name, field.type, field_name), context)) return false; } - else if (field.type.is_ptr && need_pointer_conversion(regular)) + else if (field.type.is_ptr && need_pointer_conversion(regular) && !need_struct_conversion(regular)) { if (!as_generator( scope_tab << scope_tab << "_external_struct." << string << " = eina.PrimitiveConversion.PointerToManaged<" << type << ">(_internal_struct." << string << ");\n") diff --git a/src/tests/efl_mono/BasicDirection.cs b/src/tests/efl_mono/BasicDirection.cs new file mode 100644 index 0000000000..cf7634d09e --- /dev/null +++ b/src/tests/efl_mono/BasicDirection.cs @@ -0,0 +1,34 @@ +using System; +using System.Runtime.InteropServices; +using System.Linq; + +namespace TestSuite +{ + +class TestIntDirections +{ + public static void simple_out() + { + int original = 1984; + int received; + test.Testing t = new test.TestingConcrete(); + + t.IntOut(original, out received); + + Test.AssertEquals(-original, received); + } + + public static void simple_ptr_out() + { + int original = 1984; + int received; + test.Testing t = new test.TestingConcrete(); + + t.IntPtrOut(original, out received); + + Test.AssertEquals(original*2, received); + } +} + +} + diff --git a/src/tests/efl_mono/Structs.cs b/src/tests/efl_mono/Structs.cs index 07917d0c56..20707c141b 100644 --- a/src/tests/efl_mono/Structs.cs +++ b/src/tests/efl_mono/Structs.cs @@ -266,38 +266,54 @@ class TestStructs Test.Assert(r, "Function returned false"); } - // public static void simple_ptr_in() - // { - // var simple = structSimpleWithValues(); - // test.Testing t = new test.TestingConcrete(); - // bool r = t.struct_simple_ptr_in(simple); - // Test.Assert(r, "Function returned false"); - // } + public static void simple_ptr_in() + { + var simple = structSimpleWithValues(); + int original = simple.Fint; + simple.Fstring = "Struct Ptr In"; + test.Testing t = new test.TestingConcrete(); + Test.Assert(t.StructSimplePtrIn(ref simple)); + Test.AssertEquals(-original, simple.Fint); + Test.AssertEquals("nI rtP tcurtS", simple.Fstring); + } - // public static void simple_ptr_in_own() - // { - // var simple = structSimpleWithValues(); - // test.Testing t = new test.TestingConcrete(); - // bool r = t.struct_simple_ptr_in_own(simple); - // Test.Assert(r, "Function returned false"); - // } + public static void simple_ptr_in_own() + { + var simple = structSimpleWithValues(); + int original = simple.Fint; + simple.Fstring = "Struct Ptr In Own"; + test.Testing t = new test.TestingConcrete(); + test.StructSimple result = t.StructSimplePtrInOwn(ref simple); + Test.AssertEquals(-original, result.Fint); + Test.AssertEquals("nwO nI rtP tcurtS", result.Fstring); + } public static void simple_out() { var simple = new test.StructSimple(); test.Testing t = new test.TestingConcrete(); - bool r = t.StructSimpleOut(ref simple); + bool r = t.StructSimpleOut(out simple); Test.Assert(r, "Function returned false"); checkStructSimple(simple); } - // public static void simple_ptr_out() - // { - // } + public static void simple_ptr_out() + { + test.StructSimple simple; + test.Testing t = new test.TestingConcrete(); + test.StructSimple result = t.StructSimplePtrOut(out simple); + Test.AssertEquals(result.Fint, simple.Fint); + Test.AssertEquals(result.Fstring, simple.Fstring); + } - // public static void simple_ptr_out_own() - // { - // } + public static void simple_ptr_out_own() + { + test.StructSimple simple; + test.Testing t = new test.TestingConcrete(); + test.StructSimple result = t.StructSimplePtrOutOwn(out simple); + Test.AssertEquals(result.Fint, simple.Fint); + Test.AssertEquals(simple.Fstring, "Ptr Out Own"); + } public static void simple_return() { @@ -306,14 +322,186 @@ class TestStructs checkStructSimple(simple); } - // public static void simple_ptr_return() - // { - // } + public static void simple_ptr_return() + { + test.Testing t = new test.TestingConcrete(); + var simple = t.StructSimplePtrReturn(); + Test.AssertEquals(simple.Fstring, "Ret Ptr"); + } - // public static void simple_ptr_return_own() - // { - // } + public static void simple_ptr_return_own() + { + test.Testing t = new test.TestingConcrete(); + var simple = t.StructSimplePtrReturnOwn(); + Test.AssertEquals(simple.Fstring, "Ret Ptr Own"); + } + public class StructReturner : test.TestingInherit + { + public test.StructSimple received; + public bool called; + + public StructReturner() : base(null) + { + called = false; + received = default(test.StructSimple); + } + + public override bool StructSimpleIn(test.StructSimple simple) + { + called = true; + received = simple; + + return true; + } + + public override bool StructSimplePtrIn(ref test.StructSimple simple) + { + called = true; + simple.Fstring = "Virtual Struct Ptr In"; + return true; + } + + public override test.StructSimple StructSimplePtrInOwn(ref test.StructSimple simple) + { + called = true; + received = simple; + return received; + } + + public override bool StructSimpleOut(out test.StructSimple simple) { + called = true; + simple = new test.StructSimple(); + simple.Fstring = "Virtual Struct Out"; + return true; + } + + public override test.StructSimple StructSimplePtrOut(out test.StructSimple simple) { + called = true; + // No way to explicitly define the ownership of the parameter. + simple = new test.StructSimple(); + simple.Fstring = "Virtual Struct Ptr Out"; + return simple; + } + + public override test.StructSimple StructSimplePtrOutOwn(out test.StructSimple simple) { + called = true; + // No way to explicitly define the ownership of the parameter. + simple = new test.StructSimple(); + simple.Fstring = "Virtual Struct Ptr Out Own"; + return simple; + } + + public override test.StructSimple StructSimpleReturn() + { + called = true; + var simple = new test.StructSimple(); + simple.Fstring = "Virtual Struct Return"; + return simple; + } + + public override test.StructSimple StructSimplePtrReturn() + { + called = true; + var simple = new test.StructSimple(); + simple.Fstring = "Virtual Struct Ptr Return"; + return simple; + } + + public override test.StructSimple StructSimplePtrReturnOwn() + { + called = true; + var simple = new test.StructSimple(); + simple.Fstring = "Virtual Struct Ptr Return Own"; + return simple; + } + } + + public static void simple_in_virtual() + { + StructReturner t = new StructReturner(); + var simple = structSimpleWithValues(); + simple.Fstring = "Virtual Struct In"; + + t.CallStructSimpleIn(simple); + Test.Assert(t.called); + Test.AssertEquals(simple.Fstring, t.received.Fstring); + } + + public static void simple_ptr_in_virtual() + { + StructReturner t = new StructReturner(); + var simple = structSimpleWithValues(); + string reference = "Virtual Struct Ptr In"; + + t.CallStructSimplePtrIn(ref simple); + Test.Assert(t.called); + Test.AssertEquals(simple.Fstring, reference); + } + + public static void simple_ptr_in_own_virtual() + { + StructReturner t = new StructReturner(); + var simple = structSimpleWithValues(); + simple.Fstring = "Virtual Struct Ptr In Own"; + + t.CallStructSimplePtrInOwn(ref simple); + Test.Assert(t.called); + Test.AssertEquals(t.received.Fstring, simple.Fstring); + } + + public static void simple_out_virtual() + { + StructReturner t = new StructReturner(); + test.StructSimple simple; + t.CallStructSimpleOut(out simple); + Test.Assert(t.called, "override was not called"); + Test.AssertEquals("Virtual Struct Out", simple.Fstring); + } + + public static void simple_ptr_out_virtual() + { + StructReturner t = new StructReturner(); + test.StructSimple simple; + t.CallStructSimplePtrOut(out simple); + Test.Assert(t.called, "override was not called"); + Test.AssertEquals("Virtual Struct Ptr Out", simple.Fstring); + } + + public static void simple_ptr_out_own_virtual() + { + StructReturner t = new StructReturner(); + test.StructSimple simple; + t.CallStructSimplePtrOutOwn(out simple); + Test.Assert(t.called, "override was not called"); + Test.AssertEquals("Virtual Struct Ptr Out Own", simple.Fstring); + } + + public static void simple_return_virtual() + { + StructReturner t = new StructReturner(); + test.StructSimple simple = t.CallStructSimpleReturn(); + Test.Assert(t.called, "override was not called"); + Test.AssertEquals("Virtual Struct Return", simple.Fstring); + } + + public static void simple_ptr_return_virtual() + { + StructReturner t = new StructReturner(); + test.StructSimple simple = t.CallStructSimplePtrReturn(); + Test.Assert(t.called, "override was not called"); + Test.AssertEquals("Virtual Struct Ptr Return", simple.Fstring); + } + + public static void simple_ptr_return_own_virtual() + { + StructReturner t = new StructReturner(); + test.StructSimple simple = t.CallStructSimplePtrReturnOwn(); + Test.Assert(t.called, "override was not called"); + Test.AssertEquals("Virtual Struct Ptr Return Own", simple.Fstring); + } + + // Complex Structs public static void complex_in() { var complex = structComplexWithValues(); @@ -334,7 +522,7 @@ class TestStructs { var complex = new test.StructComplex(); test.Testing t = new test.TestingConcrete(); - bool r = t.StructComplexOut(ref complex); + bool r = t.StructComplexOut(out complex); Test.Assert(r, "Function returned false"); checkStructComplex(complex); } diff --git a/src/tests/efl_mono/libefl_mono_native_test.c b/src/tests/efl_mono/libefl_mono_native_test.c index f96666380b..04fd12053f 100644 --- a/src/tests/efl_mono/libefl_mono_native_test.c +++ b/src/tests/efl_mono/libefl_mono_native_test.c @@ -44,7 +44,8 @@ typedef struct Test_Testing_Data Eina_Free_Cb free_cb; Eina_Error error_code; Eina_Value *stored_value; - + Test_StructSimple stored_struct; + int stored_int; } Test_Testing_Data; typedef struct Test_Numberwrapper_Data @@ -100,6 +101,17 @@ Efl_Object *_test_testing_return_object(Eo *obj, EINA_UNUSED Test_Testing_Data * return obj; } +void _test_testing_int_out(EINA_UNUSED Eo *obj, EINA_UNUSED Test_Testing_Data *pd, int x, int *y) +{ + *y = -x; +} + +void _test_testing_int_ptr_out(EINA_UNUSED Eo *obj, Test_Testing_Data *pd, int x, int **y) +{ + pd->stored_int = x * 2; + *y = &pd->stored_int; +} + const char *_test_testing_in_string(EINA_UNUSED Eo *obj, EINA_UNUSED Test_Testing_Data *pd, const char *str) { const char *ret = malloc(sizeof(char)*(strlen(str) + 1)); @@ -3342,20 +3354,34 @@ Eina_Bool _test_testing_struct_simple_in(EINA_UNUSED Eo *obj, EINA_UNUSED Test_T return check_and_modify_struct_simple(&simple); } -EOLIAN -Eina_Bool _test_testing_struct_simple_ptr_in(EINA_UNUSED Eo *obj, EINA_UNUSED Test_Testing_Data *pd, Test_StructSimple *simple) +static void _reverse_string(char *str) { - (void) simple; - EINA_LOG_ERR("Not implemented!"); - return EINA_FALSE; + int len = strlen(str); + if (len > 0) { + for (int i=0, k=len-1; i < len/2; i++, k--) { + char tmp = str[k]; + str[k] = str[i]; + str[i] = tmp; + } + } } EOLIAN -Eina_Bool _test_testing_struct_simple_ptr_in_own(EINA_UNUSED Eo *obj, EINA_UNUSED Test_Testing_Data *pd, Test_StructSimple *simple) +Eina_Bool _test_testing_struct_simple_ptr_in(EINA_UNUSED Eo *obj, EINA_UNUSED Test_Testing_Data *pd, Test_StructSimple *simple) { - (void) simple; - EINA_LOG_ERR("Not implemented!"); - return EINA_FALSE; + simple->fint = -simple->fint; + _reverse_string(simple->fstring); + return EINA_TRUE; +} + +EOLIAN +Test_StructSimple _test_testing_struct_simple_ptr_in_own(EINA_UNUSED Eo *obj, EINA_UNUSED Test_Testing_Data *pd, Test_StructSimple *simple) +{ + Test_StructSimple ret = *simple; + free(simple); + ret.fint = -ret.fint; + _reverse_string(ret.fstring); + return ret; } EOLIAN @@ -3373,19 +3399,20 @@ Eina_Bool _test_testing_struct_simple_out(EINA_UNUSED Eo *obj, EINA_UNUSED Test_ } EOLIAN -Eina_Bool _test_testing_struct_simple_ptr_out(EINA_UNUSED Eo *obj, EINA_UNUSED Test_Testing_Data *pd, Test_StructSimple **simple) +Test_StructSimple _test_testing_struct_simple_ptr_out(EINA_UNUSED Eo *obj, Test_Testing_Data *pd, Test_StructSimple **simple) { - (void) simple; - EINA_LOG_ERR("Not implemented!"); - return EINA_FALSE; + struct_simple_with_values(&pd->stored_struct); + *simple = &pd->stored_struct; + return **simple; } EOLIAN -Eina_Bool _test_testing_struct_simple_ptr_out_own(EINA_UNUSED Eo *obj, EINA_UNUSED Test_Testing_Data *pd, Test_StructSimple **simple) +Test_StructSimple _test_testing_struct_simple_ptr_out_own(EINA_UNUSED Eo *obj, EINA_UNUSED Test_Testing_Data *pd, Test_StructSimple **simple) { - (void) simple; - EINA_LOG_ERR("Not implemented!"); - return EINA_FALSE; + *simple = malloc(sizeof(Test_StructSimple)); + struct_simple_with_values(*simple); + (*simple)->fstring = "Ptr Out Own"; + return **simple; } EOLIAN @@ -3399,15 +3426,72 @@ Test_StructSimple _test_testing_struct_simple_return(EINA_UNUSED Eo *obj, EINA_U EOLIAN Test_StructSimple *_test_testing_struct_simple_ptr_return(EINA_UNUSED Eo *obj, EINA_UNUSED Test_Testing_Data *pd) { - EINA_LOG_ERR("Not implemented!"); - return NULL; + struct_simple_with_values(&pd->stored_struct); + pd->stored_struct.fstring = "Ret Ptr"; + return &pd->stored_struct; } EOLIAN Test_StructSimple *_test_testing_struct_simple_ptr_return_own(EINA_UNUSED Eo *obj, EINA_UNUSED Test_Testing_Data *pd) { - EINA_LOG_ERR("Not implemented!"); - return NULL; + Test_StructSimple *ret = malloc(sizeof(Test_StructSimple)); + struct_simple_with_values(ret); + ret->fstring = "Ret Ptr Own"; + return ret; +} + +EOLIAN +void _test_testing_call_struct_simple_in(Eo *obj, EINA_UNUSED Test_Testing_Data *pd, Test_StructSimple simple) +{ + test_testing_struct_simple_in(obj, simple); +} + +EOLIAN +void _test_testing_call_struct_simple_ptr_in(Eo *obj, EINA_UNUSED Test_Testing_Data *pd, Test_StructSimple *simple) +{ + test_testing_struct_simple_ptr_in(obj, simple); +} + +EOLIAN +void _test_testing_call_struct_simple_ptr_in_own(Eo *obj, EINA_UNUSED Test_Testing_Data *pd, Test_StructSimple *simple) +{ + test_testing_struct_simple_ptr_in_own(obj, simple); +} + +EOLIAN +void _test_testing_call_struct_simple_out(Eo *obj, EINA_UNUSED Test_Testing_Data *pd, Test_StructSimple *simple) +{ + test_testing_struct_simple_out(obj, simple); +} + +EOLIAN +void _test_testing_call_struct_simple_ptr_out(Eo *obj, EINA_UNUSED Test_Testing_Data *pd, Test_StructSimple **simple) +{ + test_testing_struct_simple_ptr_out(obj, simple); +} + +EOLIAN +void _test_testing_call_struct_simple_ptr_out_own(Eo *obj, EINA_UNUSED Test_Testing_Data *pd, Test_StructSimple **simple) +{ + test_testing_struct_simple_ptr_out_own(obj, simple); +} + +EOLIAN +Test_StructSimple _test_testing_call_struct_simple_return(Eo *obj, EINA_UNUSED Test_Testing_Data *pd) +{ + return test_testing_struct_simple_return(obj); +} + +EOLIAN +Test_StructSimple *_test_testing_call_struct_simple_ptr_return(Eo *obj, EINA_UNUSED Test_Testing_Data *pd) +{ + return test_testing_struct_simple_ptr_return(obj); +} + +EOLIAN +Test_StructSimple *_test_testing_call_struct_simple_ptr_return_own(Eo *obj, EINA_UNUSED Test_Testing_Data *pd) +{ + return test_testing_struct_simple_ptr_return_own(obj); } // with complex types diff --git a/src/tests/efl_mono/test_testing.eo b/src/tests/efl_mono/test_testing.eo index a65b4db8da..c2d3edcd2e 100644 --- a/src/tests/efl_mono/test_testing.eo +++ b/src/tests/efl_mono/test_testing.eo @@ -87,6 +87,20 @@ class Test.Testing (Efl.Object) { return: Test.Testing; } + int_out { + params { + @in x: int; + @out y: int; + } + } + + int_ptr_out { + params { + @in x: int; + @out y: ptr(int); + } + } + in_stringshare { params { @in v: stringshare; @@ -1355,19 +1369,19 @@ class Test.Testing (Efl.Object) { return: bool; } - // struct_simple_ptr_in { - // params { - // @in simple: ptr(Test.StructSimple); - // } - // return: bool; - // } - // - // struct_simple_ptr_in_own { - // params { - // @in simple: ptr(Test.StructSimple) @owned; - // } - // return: bool; - // } + struct_simple_ptr_in { + params { + @in simple: ptr(Test.StructSimple); + } + return: bool; + } + + struct_simple_ptr_in_own { + params { + @in simple: ptr(Test.StructSimple) @owned; + } + return: Test.StructSimple; + } struct_simple_out { params { @@ -1376,31 +1390,79 @@ class Test.Testing (Efl.Object) { return: bool; } - // struct_simple_ptr_out { - // params { - // @out simple: ptr(Test.StructSimple); - // } - // return: bool; - // } - // - // struct_simple_ptr_out_own { - // params { - // @out simple: ptr(Test.StructSimple) @owned; - // } - // return: bool; - // } + struct_simple_ptr_out { + params { + @out simple: ptr(Test.StructSimple); + } + return: Test.StructSimple; + } + + struct_simple_ptr_out_own { + params { + @out simple: ptr(Test.StructSimple) @owned; + } + return: Test.StructSimple; + } struct_simple_return { return: Test.StructSimple; } - // struct_simple_ptr_return { - // return: ptr(Test.StructSimple); - // } - // - // struct_simple_ptr_return_own { - // return: ptr(Test.StructSimple) @owned; - // } + struct_simple_ptr_return { + return: ptr(Test.StructSimple); + } + + struct_simple_ptr_return_own { + return: ptr(Test.StructSimple) @owned; + } + + call_struct_simple_in { + params { + @in simple: Test.StructSimple; + } + } + + call_struct_simple_ptr_in { + params { + @in simple: ptr(Test.StructSimple); + } + } + + call_struct_simple_ptr_in_own { + params { + @in simple: ptr(Test.StructSimple) @owned; + } + } + + call_struct_simple_out { + params { + @out simple: Test.StructSimple; + } + } + + call_struct_simple_ptr_out { + params { + @out simple: ptr(Test.StructSimple); + } + } + + call_struct_simple_ptr_out_own { + params { + @out simple: ptr(Test.StructSimple) @owned; + } + } + + call_struct_simple_return { + return: Test.StructSimple; + } + + call_struct_simple_ptr_return { + return: ptr(Test.StructSimple); + } + + call_struct_simple_ptr_return_own { + return: ptr(Test.StructSimple) @owned; + } struct_complex_in { params { @@ -1409,19 +1471,19 @@ class Test.Testing (Efl.Object) { return: bool; } - // struct_complex_ptr_in { - // params { - // @in complex: ptr(Test.StructComplex); - // } - // return: bool; - // } - // - // struct_complex_ptr_in_own { - // params { - // @in complex: ptr(Test.StructComplex) @owned; - // } - // return: bool; - // } + struct_complex_ptr_in { + params { + @in complex: ptr(Test.StructComplex); + } + return: bool; + } + + struct_complex_ptr_in_own { + params { + @in complex: ptr(Test.StructComplex) @owned; + } + return: bool; + } struct_complex_out { params {