Unverified Commit ec2608e8 authored by Roberto Iffland's avatar Roberto Iffland Committed by GitHub
Browse files

Added support for multiple return values via ValueTuple (#477)



* Added support for multiple return values via ValueTuple

* Fixed .net46 build by conditionally removing tuple support

---------
Co-authored-by: default avatarRoberto Iffland <roberto.iffland@spektra-dresden.com>
parent 251f40a9
...@@ -136,9 +136,16 @@ namespace NLua.Method ...@@ -136,9 +136,16 @@ namespace NLua.Method
} }
} }
int PushReturnValue(LuaState luaState) /*
* Pushes all return values onto the stack (including out and ref parameters).
* Returns the number of return values.
*/
int PushReturnValue(LuaState luaState, object returnValue)
{ {
int nReturnValues = 0; int nReturnValues = 0;
if (!_lastCalledMethod.IsReturnVoid)
nReturnValues = _translator.PushMultiple(luaState, returnValue);
// Pushes out and ref return values // Pushes out and ref return values
for (int index = 0; index < _lastCalledMethod.outList.Length; index++) for (int index = 0; index < _lastCalledMethod.outList.Length; index++)
{ {
...@@ -146,13 +153,7 @@ namespace NLua.Method ...@@ -146,13 +153,7 @@ namespace NLua.Method
_translator.Push(luaState, _lastCalledMethod.args[_lastCalledMethod.outList[index]]); _translator.Push(luaState, _lastCalledMethod.args[_lastCalledMethod.outList[index]]);
} }
// If not return void,we need add 1, return nReturnValues;
// or we will lost the function's return value
// when call dotnet function like "int foo(arg1,out arg2,out arg3)" in Lua code
if (!_lastCalledMethod.IsReturnVoid && nReturnValues > 0)
nReturnValues++;
return nReturnValues < 1 ? 1 : nReturnValues;
} }
int CallInvoke(LuaState luaState, MethodBase method, object targetObject) int CallInvoke(LuaState luaState, MethodBase method, object targetObject)
...@@ -169,7 +170,7 @@ namespace NLua.Method ...@@ -169,7 +170,7 @@ namespace NLua.Method
else else
result = method.Invoke(targetObject, _lastCalledMethod.args); result = method.Invoke(targetObject, _lastCalledMethod.args);
_translator.Push(luaState, result); return PushReturnValue(luaState, result);
} }
catch (TargetInvocationException e) catch (TargetInvocationException e)
{ {
...@@ -182,8 +183,6 @@ namespace NLua.Method ...@@ -182,8 +183,6 @@ namespace NLua.Method
{ {
return SetPendingException(e); return SetPendingException(e);
} }
return PushReturnValue(luaState);
} }
bool IsMethodCached(LuaState luaState, int numArgsPassed, int skipParams) bool IsMethodCached(LuaState luaState, int numArgsPassed, int skipParams)
...@@ -291,10 +290,9 @@ namespace NLua.Method ...@@ -291,10 +290,9 @@ namespace NLua.Method
} }
MethodInfo concreteMethod = methodToCall.MakeGenericMethod(typeArgs.ToArray()); MethodInfo concreteMethod = methodToCall.MakeGenericMethod(typeArgs.ToArray());
var result = concreteMethod.Invoke(targetObject, _lastCalledMethod.args);
_translator.Push(luaState, concreteMethod.Invoke(targetObject, _lastCalledMethod.args)); return PushReturnValue(luaState, result);
return PushReturnValue(luaState);
} }
/* /*
......
...@@ -16,6 +16,7 @@ using NLua.Extensions; ...@@ -16,6 +16,7 @@ using NLua.Extensions;
using LuaState = KeraLua.Lua; using LuaState = KeraLua.Lua;
using LuaNativeFunction = KeraLua.LuaFunction; using LuaNativeFunction = KeraLua.LuaFunction;
using System.Runtime.CompilerServices;
namespace NLua namespace NLua
{ {
...@@ -1076,6 +1077,28 @@ namespace NLua ...@@ -1076,6 +1077,28 @@ namespace NLua
PushObject(luaState, o, "luaNet_metatable"); PushObject(luaState, o, "luaNet_metatable");
} }
/*
* If the given object is an ITuple value type (e.g. ValueTuple) all elements
* of it are pushed onto the stack. Otherwise the element is pushed as is,
* according to it's type.
*/
public int PushMultiple(LuaState luaState, object o)
{
#if NETCOREAPP1_1_OR_GREATER
if (o is ITuple tuple && o.GetType().IsValueType)
{
for (int i = 0; i < tuple.Length; ++i)
{
Push(luaState, tuple[i]);
}
return tuple.Length;
}
#endif
Push(luaState, o);
return 1;
}
/* /*
* Checks if the method matches the arguments in the Lua stack, getting * Checks if the method matches the arguments in the Lua stack, getting
* the arguments if it does. * the arguments if it does.
......
...@@ -1244,6 +1244,39 @@ namespace NLuaTest ...@@ -1244,6 +1244,39 @@ namespace NLuaTest
Assert.AreEqual(5, b); Assert.AreEqual(5, b);
} }
} }
#if NETCOREAPP1_1_OR_GREATER
/*
* Tests calling of an object's method with multiple return values (Tuple).
*/
[Test]
public void CallObjectMethodWithMultipleReturnValues()
{
using (Lua lua = new Lua())
{
lua["netobj"] = new TestTypes.TestClass();
var ret = lua.DoString("return netobj:returnPair()");
Assert.AreEqual(2, ret.Length);
Assert.AreEqual(5, ret[0]);
Assert.AreEqual("five", ret[1]);
}
}
/*
* Tests calling of an object's method with multiple return values (Tuple) and out parameter.
*/
[Test]
public void CallObjectMethodWithMultipleReturnValuesAndOutParam()
{
using (Lua lua = new Lua())
{
lua["netobj"] = new TestTypes.TestClass();
var ret = lua.DoString("return netobj:returnPairWithOutParam()");
Assert.AreEqual(3, ret.Length);
Assert.AreEqual(5, ret[0]);
Assert.AreEqual("five", ret[1]);
Assert.AreEqual(true, ret[2]);
}
}
#endif
/* /*
* Tests calling of an object's method with ref params * Tests calling of an object's method with ref params
*/ */
......
...@@ -146,6 +146,19 @@ namespace NLuaTest.TestTypes ...@@ -146,6 +146,19 @@ namespace NLuaTest.TestTypes
return arg; return arg;
} }
#if NETCOREAPP1_1_OR_GREATER
public (int, string) returnPair()
{
return (5, "five");
}
public (int, string) returnPairWithOutParam(out bool b)
{
b = true;
return (5, "five");
}
#endif
/* /*
* Returns the number of arguments received. * Returns the number of arguments received.
*/ */
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment