Skip to content

Commit

Permalink
Added delegate return value support for stack value range.
Browse files Browse the repository at this point in the history
  • Loading branch information
Quahu committed Jun 2, 2024
1 parent b1ca23b commit 27b295e
Show file tree
Hide file tree
Showing 3 changed files with 114 additions and 25 deletions.
61 changes: 43 additions & 18 deletions src/Laylua.Tests/Tests/Marshaler/LuaMarshalerDelegateTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -68,24 +68,49 @@ public void Delegate_Int32_Int32_Int32_ReceivesValidValues()
Assert.That(result3, Is.EqualTo(3));
}

// TODO: LuaStackValueRange return?
// [Test]
// public void CallVariadicFuncFromLua()
// {
// lua["func"] = (LuaStackValueRange args) =>
// {
// return args;
// };
//
// lua.Execute("result = { func(1, 2, 3) }");
//
// using (var result = lua.GetGlobal<LuaTable>("result")!)
// using (result.AsSequenceArray(out var actual))
// {
// var expected = new object[] { 1, 2, 3 };
// CollectionAssert.AreEqual(expected, actual);
// }
// }
[Test]
public void Delegate_LuaStackValueRange_ReturnsVariadicArguments()
{
// Arrange
Lua.SetGlobal("func", (LuaStackValueRange args) =>
{
return args;
});

// Act
using var result = Lua.Evaluate("return func(1, 2, 3)");
var actual = new List<int>();
foreach (var value in result)
{
actual.Add(value.GetValue<int>());
}

// Assert
Assert.That(result.Count, Is.EqualTo(3));
Assert.That(actual, Is.EquivalentTo(new[] { 1, 2, 3 }));
}

[Test]
public void Delegate_LuaStackValueRange_ReturningLuaFunctionResults_ReturnsVariadicArguments()
{
// Arrange
Lua.SetGlobal("func", () =>
{
return Lua.Evaluate("return 1, 2, 3");
});

// Act
using var result = Lua.Evaluate("return func()");
var actual = new List<int>();
foreach (var value in result)
{
actual.Add(value.GetValue<int>());
}

// Assert
Assert.That(result.Count, Is.EqualTo(3));
Assert.That(actual, Is.EquivalentTo(new[] { 1, 2, 3 }));
}

[Test]
public void Delegate_ParamsDouble_ReturnsValidDoubleValues()
Expand Down
24 changes: 24 additions & 0 deletions src/Laylua/Library/LuaFunctionResults.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,17 @@ public readonly int Count
}
}

/// <inheritdoc cref="LuaStackValueRange.this[int]"/>
public LuaStackValue this[int index]
{
get
{
ThrowIfDisposed();

return _range[index];
}
}

/// <inheritdoc cref="LuaStackValueRange.First"/>
public readonly LuaStackValue First
{
Expand All @@ -62,6 +73,19 @@ public readonly LuaStackValue Last
}
}

/// <summary>
/// Gets the underlying <see cref="LuaStackValueRange"/>.
/// </summary>
public readonly LuaStackValueRange Range
{
get
{
ThrowIfDisposed();

return _range;
}
}

private readonly LuaStackValueRange _range;
private bool _isDisposed;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ public static class UserDataDescriptorUtilities

private static readonly ConstructorInfo _luaStackValueRangeConstructor;
private static readonly PropertyInfo _luaStackValueRangeGetItemProperty;
private static readonly PropertyInfo _luaStackValueRangeCountProperty;
private static readonly MethodInfo _luaStackValueRangePushValuesMethod;
private static readonly PropertyInfo _luaFunctionResultsRangeProperty;

private static readonly MethodInfo _luaMarshalerTryToObjectMethod;

Expand Down Expand Up @@ -52,6 +55,18 @@ static UserDataDescriptorUtilities()
Guard.IsNotNull(luaStackValueRangeGetItemProperty);
_luaStackValueRangeGetItemProperty = luaStackValueRangeGetItemProperty;

var luaStackValueRangeCountProperty = typeof(LuaStackValueRange).GetProperty(nameof(LuaStackValueRange.Count), BindingFlags.Instance | BindingFlags.Public);
Guard.IsNotNull(luaStackValueRangeCountProperty);
_luaStackValueRangeCountProperty = luaStackValueRangeCountProperty;

var luaStackValueRangePushValuesMethod = typeof(LuaStackValueRange).GetMethod(nameof(LuaStackValueRange.PushValues), BindingFlags.Instance | BindingFlags.Public);
Guard.IsNotNull(luaStackValueRangePushValuesMethod);
_luaStackValueRangePushValuesMethod = luaStackValueRangePushValuesMethod;

var luaFunctionResultsRangeProperty = typeof(LuaFunctionResults).GetProperty(nameof(LuaFunctionResults.Range), BindingFlags.Instance | BindingFlags.Public);
Guard.IsNotNull(luaFunctionResultsRangeProperty);
_luaFunctionResultsRangeProperty = luaFunctionResultsRangeProperty;

var luaMarshalerTryToObjectMethod = typeof(LuaMarshaler).GetMethod(nameof(LuaMarshaler.TryGetValue), BindingFlags.Instance | BindingFlags.Public);
Guard.IsNotNull(luaMarshalerTryToObjectMethod);
_luaMarshalerTryToObjectMethod = luaMarshalerTryToObjectMethod;
Expand Down Expand Up @@ -186,6 +201,7 @@ private static MethodInvokerDelegate CreateInvoker(object? instance, MethodInfo
}

var bodyExpressions = new List<Expression>();
var variableExpressions = new List<ParameterExpression>();

// T1 arg1
// T2 arg2
Expand All @@ -196,6 +212,8 @@ private static MethodInvokerDelegate CreateInvoker(object? instance, MethodInfo
argumentVariableExpressions[i] = Expression.Variable(parameters[i].ParameterType, parameters[i].Name);
}

variableExpressions.AddRange(argumentVariableExpressions);

var isInstanceMethodInvoker = false;
Expression? instanceExpression;
ParameterExpression? instanceExpressionVariable = null;
Expand Down Expand Up @@ -239,6 +257,11 @@ private static MethodInvokerDelegate CreateInvoker(object? instance, MethodInfo
}
}

if (instanceExpressionVariable != null)
{
variableExpressions.Add(instanceExpressionVariable);
}

// @delegate(arg1, arg2, arg3);
var callDelegateExpression = Expression.Call(instanceExpression, methodInfo, argumentVariableExpressions);

Expand Down Expand Up @@ -338,11 +361,28 @@ private static MethodInvokerDelegate CreateInvoker(object? instance, MethodInfo
Expression returnCountExpression;
if (methodInfo.ReturnType != typeof(void))
{
// lua.Stack.Push(@delegate(...));
var pushMethod = _pushMethod.MakeGenericMethod(methodInfo.ReturnType);
var luaStack = Expression.Property(luaParameterExpression, nameof(Lua.Stack));
callDelegateExpression = Expression.Call(luaStack, pushMethod, callDelegateExpression);
returnCountExpression = Expression.Constant(1, typeof(int));
if (methodInfo.ReturnType == typeof(LuaStackValueRange)
|| methodInfo.ReturnType == typeof(LuaFunctionResults))
{
var returnValueVariableExpression = Expression.Variable(typeof(LuaStackValueRange), "returnValue");
variableExpressions.Add(returnValueVariableExpression);

callDelegateExpression = Expression.Call(
Expression.Assign(returnValueVariableExpression, methodInfo.ReturnType == typeof(LuaStackValueRange)
? callDelegateExpression
: Expression.Property(callDelegateExpression, _luaFunctionResultsRangeProperty)),
_luaStackValueRangePushValuesMethod);

returnCountExpression = Expression.Property(returnValueVariableExpression, _luaStackValueRangeCountProperty);
}
else
{
// lua.Stack.Push(@delegate(...));
var pushMethod = _pushMethod.MakeGenericMethod(methodInfo.ReturnType);
var luaStack = Expression.Property(luaParameterExpression, nameof(Lua.Stack));
callDelegateExpression = Expression.Call(luaStack, pushMethod, callDelegateExpression);
returnCountExpression = Expression.Constant(1, typeof(int));
}
}
else
{
Expand Down Expand Up @@ -444,11 +484,11 @@ private static MethodInvokerDelegate CreateInvoker(object? instance, MethodInfo
bodyExpressions.Add(callDelegateExpression);
bodyExpressions.Add(returnCountExpression);

Expression bodyExpression = Expression.Block(instanceExpressionVariable != null ? argumentVariableExpressions.Prepend(instanceExpressionVariable) : argumentVariableExpressions, bodyExpressions);
Expression bodyExpression = Expression.Block(variableExpressions, bodyExpressions);

if (disposeArgumentExpressions.Count > 0)
{
bodyExpression = Expression.TryFinally(bodyExpression, Expression.Block(argumentVariableExpressions, disposeArgumentExpressions));
bodyExpression = Expression.TryFinally(bodyExpression, Expression.Block(variableExpressions, disposeArgumentExpressions));
}

var lambdaExpression = Expression.Lambda<MethodInvokerDelegate>(bodyExpression, luaParameterExpression, argumentsParameterExpression);
Expand Down

0 comments on commit 27b295e

Please sign in to comment.