CoroutineLibrary.cs 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. using Lua.Runtime;
  2. namespace Lua.Standard;
  3. public sealed class CoroutineLibrary
  4. {
  5. public static readonly CoroutineLibrary Instance = new();
  6. public CoroutineLibrary()
  7. {
  8. Functions = [
  9. new("create", Create),
  10. new("resume", Resume),
  11. new("running", Running),
  12. new("status", Status),
  13. new("wrap", Wrap),
  14. new("yield", Yield),
  15. ];
  16. }
  17. public readonly LuaFunction[] Functions;
  18. public ValueTask<int> Create(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
  19. {
  20. var arg0 = context.GetArgument<LuaFunction>(0);
  21. buffer.Span[0] = new LuaCoroutine(arg0, true);
  22. return new(1);
  23. }
  24. public ValueTask<int> Resume(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
  25. {
  26. var thread = context.GetArgument<LuaThread>(0);
  27. return thread.ResumeAsync(context, buffer, cancellationToken);
  28. }
  29. public ValueTask<int> Running(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
  30. {
  31. buffer.Span[0] = context.Thread;
  32. buffer.Span[1] = context.Thread == context.State.MainThread;
  33. return new(2);
  34. }
  35. public ValueTask<int> Status(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
  36. {
  37. var thread = context.GetArgument<LuaThread>(0);
  38. buffer.Span[0] = thread.GetStatus() switch
  39. {
  40. LuaThreadStatus.Normal => "normal",
  41. LuaThreadStatus.Suspended => "suspended",
  42. LuaThreadStatus.Running => "running",
  43. LuaThreadStatus.Dead => "dead",
  44. _ => "",
  45. };
  46. return new(1);
  47. }
  48. public ValueTask<int> Wrap(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
  49. {
  50. var arg0 = context.GetArgument<LuaFunction>(0);
  51. var thread = new LuaCoroutine(arg0, false);
  52. buffer.Span[0] = new CsClosure("wrap", [thread],static async (context, buffer, cancellationToken) =>
  53. {
  54. var thread = context.GetCsClosure()!.UpValues[0].Read<LuaThread>();
  55. if (thread is not LuaCoroutine coroutine)
  56. {
  57. return await thread.ResumeAsync(context, buffer, cancellationToken);
  58. }
  59. var stack = context.Thread.Stack;
  60. var frameBase = stack.Count;
  61. stack.Push(thread);
  62. stack.PushRange(context.Arguments);
  63. context.Thread.PushCallStackFrame(new()
  64. {
  65. Base = frameBase,
  66. VariableArgumentCount = 0,
  67. Function = coroutine.Function,
  68. });
  69. try
  70. {
  71. var resultCount = await thread.ResumeAsync(context with
  72. {
  73. ArgumentCount = context.ArgumentCount + 1,
  74. FrameBase = frameBase,
  75. }, buffer, cancellationToken);
  76. buffer.Span[1..].CopyTo(buffer.Span[0..]);
  77. return resultCount - 1;
  78. }
  79. finally
  80. {
  81. context.Thread.PopCallStackFrame();
  82. }
  83. });
  84. return new(1);
  85. }
  86. public ValueTask<int> Yield(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
  87. {
  88. return context.Thread.YieldAsync(context, buffer, cancellationToken);
  89. }
  90. }