DisposableStack.cs 2.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. using Jint.Native.Object;
  2. using Jint.Runtime;
  3. using Jint.Runtime.Interop;
  4. namespace Jint.Native.Disposable;
  5. internal enum DisposableState
  6. {
  7. Pending,
  8. Disposed,
  9. }
  10. internal sealed class DisposableStack : ObjectInstance
  11. {
  12. internal readonly DisposeHint _hint;
  13. private DisposeCapability _disposeCapability;
  14. public DisposableStack(Engine engine, DisposeHint hint) : base(engine)
  15. {
  16. _hint = hint;
  17. State = DisposableState.Pending;
  18. _disposeCapability = new DisposeCapability(engine);
  19. }
  20. public DisposableState State { get; private set; }
  21. public JsValue Dispose()
  22. {
  23. if (State == DisposableState.Disposed)
  24. {
  25. return Undefined;
  26. }
  27. State = DisposableState.Disposed;
  28. var completion = _disposeCapability.DisposeResources(new Completion(CompletionType.Normal, Undefined, _engine.GetLastSyntaxElement()));
  29. if (completion.Type == CompletionType.Throw)
  30. {
  31. ExceptionHelper.ThrowJavaScriptException(_engine, completion.Value, completion);
  32. }
  33. return completion.Value;
  34. }
  35. public void Defer(JsValue onDispose)
  36. {
  37. AddDisposableResource(Undefined, _hint, onDispose.GetCallable(_engine.Realm));
  38. }
  39. public JsValue Use(JsValue value)
  40. {
  41. AddDisposableResource(value, _hint);
  42. return value;
  43. }
  44. public JsValue Adopt(JsValue value, JsValue onDispose)
  45. {
  46. AssertNotDisposed();
  47. var callable = onDispose.GetCallable(_engine.Realm);
  48. JsCallDelegate closure = (_, _) =>
  49. {
  50. callable.Call(Undefined, value);
  51. return Undefined;
  52. };
  53. var f = new ClrFunction(_engine, string.Empty, closure);
  54. AddDisposableResource(Undefined, DisposeHint.Sync, f);
  55. return value;
  56. }
  57. public JsValue Move(DisposableStack newDisposableStack)
  58. {
  59. AssertNotDisposed();
  60. newDisposableStack.State = DisposableState.Pending;
  61. newDisposableStack._disposeCapability = this._disposeCapability;
  62. this._disposeCapability = new DisposeCapability(_engine);
  63. State = DisposableState.Disposed;
  64. return newDisposableStack;
  65. }
  66. private void AddDisposableResource(JsValue v, DisposeHint hint, ICallable? method = null)
  67. {
  68. AssertNotDisposed();
  69. _disposeCapability.AddDisposableResource(v, hint, method);
  70. }
  71. private void AssertNotDisposed()
  72. {
  73. if (State == DisposableState.Disposed)
  74. {
  75. ExceptionHelper.ThrowReferenceError(_engine.Realm, "Stack already disposed.");
  76. }
  77. }
  78. }