csharp: Fix support for ptr(structs)

In general, ptr(struct) parameters behavior depends whether the
parameter has the @owned modifier or not.

If there is no @owned parameter (meaning no transfer of ownership
happens) and it is a "complex" struct, with reference type fields
(like strings), the struct is converted to the respective
<Struct>Internal struct and passed with "ref" to the DllImport'd
function. For @in parameters, after the function it returns, this
intermediate struct is converted to the public struct type and
assigned to the original parameter, updating it to the external
world.

When we have ownership transfers, the structure is copied to unmanaged
memory and given to the callee. We can't send managed memory directly as
the callee may try to free it. On the managed side, the original struct
is left to be garbage collected normally.
This commit is contained in:
Lauro Moura 2018-03-15 20:32:39 -03:00 committed by Felipe Magno de Almeida
parent 7c543d3c86
commit 2705ea8531
11 changed files with 640 additions and 123 deletions

View File

@ -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 \

View File

@ -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;

View File

@ -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<attributes::regular_type_def>(&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)

View File

@ -16,6 +16,16 @@ struct marshall_annotation_visitor_generate;
template <typename OutputIterator, typename Context>
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<OutputIterator, Context>{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 <typename OutputIterator, typename Context>
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)

View File

@ -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);
}

View File

@ -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<int, 1> {};
}
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<int, 1> {};
}
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<int, 1> {};
}
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<attributes::regular_type_def>(&param.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<attributes::regular_type_def>(&param.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<attributes::regular_type_def>(&param.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 <typename OutputIterator, typename Context>
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 <typename OutputIterator, typename Context>
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<attributes::regular_type_def>(&param.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<attributes::regular_type_def>(&param.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 <typename OutputIterator, typename Context>
@ -669,7 +708,7 @@ struct convert_out_variable_generator
return true;
auto regular = efl::eina::get<attributes::regular_type_def>(&param.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<attributes::regular_type_def>(&param.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 <typename OutputIterator, typename Context>
@ -828,11 +868,17 @@ struct convert_out_assign_generator
return true;
auto regular = efl::eina::get<attributes::regular_type_def>(&param.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 <typename OutputIterator, typename Context>
bool generate(OutputIterator sink, attributes::parameter_def const& param, Context const& context) const
{
auto regular = efl::eina::get<attributes::regular_type_def>(&param.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 <typename OutputIterator, typename Context>
bool generate(OutputIterator sink, attributes::parameter_def const& param, Context const& context) const
{
auto regular = efl::eina::get<attributes::regular_type_def>(&param.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 <typename OutputIterator, typename Context>
@ -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 <typename OutputIterator, typename Context>
bool generate(OutputIterator sink, attributes::type_def const& ret_type, Context const& context) const
{
auto regular = efl::eina::get<attributes::regular_type_def>(&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<attributes::regular_type_def>(&param.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<attributes::regular_type_def>(&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"

View File

@ -94,10 +94,11 @@ struct struct_internal_definition_generator
{
if (!as_generator
(
"///<summary>Internal wrapper for struct " << string << ".</summary>\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 << "///<summary>Implicit conversion to the internal/marshalling representation.</summary>\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 << "///<summary>Implicit conversion to the managed representation.</summary>\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")

View File

@ -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);
}
}
}

View File

@ -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);
}

View File

@ -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

View File

@ -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 {