LuaFunctionExecutionContext.cs 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. using System.Runtime.CompilerServices;
  2. using System.Runtime.InteropServices;
  3. using Lua.Runtime;
  4. namespace Lua;
  5. [StructLayout(LayoutKind.Auto)]
  6. public readonly record struct LuaFunctionExecutionContext
  7. {
  8. internal LuaGlobalState GlobalState => State.GlobalState;
  9. public LuaState State { get; init; }
  10. public required int ArgumentCount { get; init; }
  11. public required int ReturnFrameBase { get; init; }
  12. // public object? AdditionalContext { get; init; }
  13. public int FrameBase => State.Stack.Count - ArgumentCount;
  14. public ReadOnlySpan<LuaValue> Arguments
  15. {
  16. get
  17. {
  18. var stack = State.Stack.AsSpan();
  19. return stack[^ArgumentCount..];
  20. }
  21. }
  22. public ReadOnlyMemory<LuaValue> ArgumentsMemory
  23. {
  24. get
  25. {
  26. var stack = State.Stack;
  27. var memory = stack.GetBufferMemory();
  28. return memory[(stack.Count - ArgumentCount)..stack.Count];
  29. }
  30. }
  31. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  32. public bool HasArgument(int index)
  33. {
  34. return ArgumentCount > index && Arguments[index].Type is not LuaValueType.Nil;
  35. }
  36. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  37. public LuaValue GetArgument(int index)
  38. {
  39. ThrowIfArgumentNotExists(index);
  40. return Arguments[index];
  41. }
  42. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  43. internal LuaValue GetArgumentOrDefault(int index, LuaValue defaultValue = default)
  44. {
  45. if (ArgumentCount <= index)
  46. {
  47. return defaultValue;
  48. }
  49. return Arguments[index];
  50. }
  51. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  52. public T GetArgument<T>(int index)
  53. {
  54. ThrowIfArgumentNotExists(index);
  55. var arg = Arguments[index];
  56. if (!arg.TryRead<T>(out var argValue))
  57. {
  58. var t = typeof(T);
  59. if ((t == typeof(int) || t == typeof(long)) && arg.TryReadNumber(out _))
  60. {
  61. LuaRuntimeException.BadArgumentNumberIsNotInteger(State, index + 1);
  62. }
  63. else if (LuaValue.TryGetLuaValueType(t, out var type))
  64. {
  65. LuaRuntimeException.BadArgument(State, index + 1, type, arg.Type);
  66. }
  67. else if (arg.Type is LuaValueType.UserData or LuaValueType.LightUserData)
  68. {
  69. LuaRuntimeException.BadArgument(State, index + 1, t.Name, arg.UnsafeRead<object>()?.GetType().ToString() ?? "userdata: 0");
  70. }
  71. else
  72. {
  73. LuaRuntimeException.BadArgument(State, index + 1, t.Name, arg.TypeToString());
  74. }
  75. }
  76. return argValue;
  77. }
  78. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  79. internal T GetArgumentOrDefault<T>(int index, T defaultValue = default!)
  80. {
  81. if (ArgumentCount <= index)
  82. {
  83. return defaultValue;
  84. }
  85. var arg = Arguments[index];
  86. if (arg.Type is LuaValueType.Nil)
  87. {
  88. return defaultValue;
  89. }
  90. if (!arg.TryRead<T>(out var argValue))
  91. {
  92. var t = typeof(T);
  93. if ((t == typeof(int) || t == typeof(long)) && arg.TryReadNumber(out _))
  94. {
  95. LuaRuntimeException.BadArgumentNumberIsNotInteger(State, index + 1);
  96. }
  97. else if (LuaValue.TryGetLuaValueType(t, out var type))
  98. {
  99. LuaRuntimeException.BadArgument(State, index + 1, type, arg.Type);
  100. }
  101. else if (arg.Type is LuaValueType.UserData or LuaValueType.LightUserData)
  102. {
  103. LuaRuntimeException.BadArgument(State, index + 1, t.Name, arg.UnsafeRead<object>()?.GetType().ToString() ?? "userdata: 0");
  104. }
  105. else
  106. {
  107. LuaRuntimeException.BadArgument(State, index + 1, t.Name, arg.TypeToString());
  108. }
  109. }
  110. return argValue;
  111. }
  112. public int Return()
  113. {
  114. State.Stack.PopUntil(ReturnFrameBase);
  115. return 0;
  116. }
  117. public int Return(LuaValue result)
  118. {
  119. var stack = State.Stack;
  120. stack.SetTop(ReturnFrameBase + 1);
  121. stack.FastGet(ReturnFrameBase) = result;
  122. return 1;
  123. }
  124. public int Return(LuaValue result0, LuaValue result1)
  125. {
  126. var stack = State.Stack;
  127. stack.SetTop(ReturnFrameBase + 2);
  128. stack.FastGet(ReturnFrameBase) = result0;
  129. stack.FastGet(ReturnFrameBase + 1) = result1;
  130. return 2;
  131. }
  132. public int Return(LuaValue result0, LuaValue result1, LuaValue result2)
  133. {
  134. var stack = State.Stack;
  135. stack.SetTop(ReturnFrameBase + 3);
  136. stack.FastGet(ReturnFrameBase) = result0;
  137. stack.FastGet(ReturnFrameBase + 1) = result1;
  138. stack.FastGet(ReturnFrameBase + 2) = result2;
  139. return 3;
  140. }
  141. public int Return(ReadOnlySpan<LuaValue> results)
  142. {
  143. var stack = State.Stack;
  144. stack.EnsureCapacity(ReturnFrameBase + results.Length);
  145. results.CopyTo(stack.GetBuffer()[ReturnFrameBase..(ReturnFrameBase + results.Length)]);
  146. stack.SetTop(ReturnFrameBase + results.Length);
  147. return results.Length;
  148. }
  149. internal int Return(LuaValue result0, ReadOnlySpan<LuaValue> results)
  150. {
  151. var stack = State.Stack;
  152. stack.EnsureCapacity(ReturnFrameBase + results.Length);
  153. stack.SetTop(ReturnFrameBase + results.Length + 1);
  154. var buffer = stack.GetBuffer();
  155. buffer[ReturnFrameBase] = result0;
  156. results.CopyTo(buffer[(ReturnFrameBase + 1)..(ReturnFrameBase + results.Length + 1)]);
  157. return results.Length + 1;
  158. }
  159. public Span<LuaValue> GetReturnBuffer(int count)
  160. {
  161. var stack = State.Stack;
  162. stack.SetTop(ReturnFrameBase + count);
  163. var buffer = stack.GetBuffer()[ReturnFrameBase..(ReturnFrameBase + count)];
  164. return buffer;
  165. }
  166. public CSharpClosure? GetCsClosure()
  167. {
  168. return State.GetCurrentFrame().Function as CSharpClosure;
  169. }
  170. internal void ThrowBadArgument(int index, string message)
  171. {
  172. LuaRuntimeException.BadArgument(State, index, State.GetCurrentFrame().Function.Name, message);
  173. }
  174. void ThrowIfArgumentNotExists(int index)
  175. {
  176. if (ArgumentCount <= index)
  177. {
  178. LuaRuntimeException.BadArgument(State, index + 1);
  179. }
  180. }
  181. }