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
}
}
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;
if (!_lastCalledMethod.IsReturnVoid)
nReturnValues = _translator.PushMultiple(luaState, returnValue);
// Pushes out and ref return values
for (int index = 0; index < _lastCalledMethod.outList.Length; index++)
{
......@@ -146,13 +153,7 @@ namespace NLua.Method
_translator.Push(luaState, _lastCalledMethod.args[_lastCalledMethod.outList[index]]);
}
// If not return void,we need add 1,
// 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;
return nReturnValues;
}
int CallInvoke(LuaState luaState, MethodBase method, object targetObject)
......@@ -169,7 +170,7 @@ namespace NLua.Method
else
result = method.Invoke(targetObject, _lastCalledMethod.args);
_translator.Push(luaState, result);
return PushReturnValue(luaState, result);
}
catch (TargetInvocationException e)
{
......@@ -182,8 +183,6 @@ namespace NLua.Method
{
return SetPendingException(e);
}
return PushReturnValue(luaState);
}
bool IsMethodCached(LuaState luaState, int numArgsPassed, int skipParams)
......@@ -291,10 +290,9 @@ namespace NLua.Method
}
MethodInfo concreteMethod = methodToCall.MakeGenericMethod(typeArgs.ToArray());
var result = concreteMethod.Invoke(targetObject, _lastCalledMethod.args);
_translator.Push(luaState, concreteMethod.Invoke(targetObject, _lastCalledMethod.args));
return PushReturnValue(luaState);
return PushReturnValue(luaState, result);
}
/*
......
......@@ -16,6 +16,7 @@ using NLua.Extensions;
using LuaState = KeraLua.Lua;
using LuaNativeFunction = KeraLua.LuaFunction;
using System.Runtime.CompilerServices;
namespace NLua
{
......@@ -1076,6 +1077,28 @@ namespace NLua
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
* the arguments if it does.
......
......@@ -1244,6 +1244,39 @@ namespace NLuaTest
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
*/
......
......@@ -146,6 +146,19 @@ namespace NLuaTest.TestTypes
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.
*/
......
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