<commit_before>#ifndef NEON_TASK_H_
#define NEON_TASK_H_

#include <nan.h>
#include <uv.h>
#include "neon.h"
#include "v8.h"

namespace neon {

class Task {
public:
  Task(v8::Isolate *isolate,
       void *rust_task,
       Neon_TaskPerformCallback perform,
       Neon_TaskCompleteCallback complete,
       v8::Local<v8::Function> callback)
    : isolate_(isolate),
      rust_task_(rust_task),
      perform_(perform),
      complete_(complete)
  {
    request_.data = this;
    result_ = nullptr;
    callback_.Reset(isolate, callback);
  }

  ~Task() {
    callback_.Reset();
  }

  void execute() {
    result_ = perform_(rust_task_);
  }

  void complete() {
    Nan::HandleScope scope;

    v8::TryCatch trycatch(isolate_);

    v8::Local<v8::Value> argv[2];
    v8::Local<v8::Value> completion;

    complete_(rust_task_, result_, &completion);

    if (trycatch.HasCaught()) {
      argv[0] = trycatch.Exception();
      argv[1] = v8::Undefined(isolate_);
    } else {
      argv[0] = v8::Null(isolate_);
      argv[1] = completion;
    }

    v8::Local<v8::Function> callback = v8::Local<v8::Function>::New(isolate_, callback_);
    callback->Call(isolate_->GetCurrentContext(), v8::Null(isolate_), 2, argv);
  }

  void *get_result() {
    return result_;
  }

  uv_work_t request_;

private:
  v8::Isolate *isolate_;
  void *rust_task_;
  Neon_TaskPerformCallback perform_;
  Neon_TaskCompleteCallback complete_;
  void *result_;
  v8::Persistent<v8::Function> callback_;
};

void execute_task(uv_work_t *request) {
  Task *task = static_cast<Task*>(request->data);
  task->execute();
}

void complete_task(uv_work_t *request) {
  Task *task = static_cast<Task*>(request->data);
  task->complete();
  delete task;<commit_msg>address issues raised in @bnoordhuis's review: - eliminate redundant resetting of `Persistent` members in destructor - save the context (ie realm) at the time the task is created - create an `Isolate::Scope` and `Context::Scope` on the stack before calling the callback - scope the `TryCatch` so it clears the pending exception before calling the callback<commit_after>#ifndef NEON_TASK_H_
#define NEON_TASK_H_

#include <uv.h>
#include "neon.h"
#include "v8.h"

namespace neon {

class Task {
public:
  Task(v8::Isolate *isolate,
       void *rust_task,
       Neon_TaskPerformCallback perform,
       Neon_TaskCompleteCallback complete,
       v8::Local<v8::Function> callback)
    : isolate_(isolate),
      rust_task_(rust_task),
      perform_(perform),
      complete_(complete)
  {
    request_.data = this;
    result_ = nullptr;
    // Save the callback to be invoked when the task completes.
    callback_.Reset(isolate, callback);
    // Save the context (aka realm) to be used when invoking the callback.
    context_.Reset(isolate, isolate->GetCurrentContext());
  }

  void execute() {
    result_ = perform_(rust_task_);
  }

  void complete() {
    // Ensure that we have all the proper scopes installed on the C++ stack before
    // invoking the callback, and use the context (i.e. realm) we saved with the task.
    v8::Isolate::Scope isolate_scope(isolate_);
    v8::HandleScope handle_scope(isolate_);
    v8::Local<v8::Context> context = v8::Local<v8::Context>::New(isolate_, context_);
    v8::Context::Scope context_scope(context);

    v8::Local<v8::Value> argv[2];

    argv[0] = v8::Null(isolate_);
    argv[1] = v8::Undefined(isolate_);

    {
      v8::TryCatch trycatch(isolate_);

      v8::Local<v8::Value> completion;

      complete_(rust_task_, result_, &completion);

      if (trycatch.HasCaught()) {
        argv[0] = trycatch.Exception();
      } else {
        argv[1] = completion;
      }
    }

    v8::Local<v8::Function> callback = v8::Local<v8::Function>::New(isolate_, callback_);
    callback->Call(context, v8::Null(isolate_), 2, argv);
  }

  void *get_result() {
    return result_;
  }

  uv_work_t request_;

private:
  v8::Isolate *isolate_;
  void *rust_task_;
  Neon_TaskPerformCallback perform_;
  Neon_TaskCompleteCallback complete_;
  void *result_;
  v8::Persistent<v8::Function> callback_;
  v8::Persistent<v8::Context> context_;
};

void execute_task(uv_work_t *request) {
  Task *task = static_cast<Task*>(request->data);
  task->execute();
}

void complete_task(uv_work_t *request) {
  Task *task = static_cast<Task*>(request->data);
  task->complete();
  delete task;
{'fraction_non_alphanumeric': 0.13340961098398169, 'fraction_numerical': 0.013501144164759725, 'mean_word_length': 3.9057239057239057, 'pattern_counts': {'":': 0, '<': 25, '<?xml version=': 0, '>': 37, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3500194', 'n_tokens_mistral': 1491, 'n_tokens_neox': 1450, 'n_words': 327}