LuaFunctionExecutionContext.cs 6.1 KB

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