// Auto generated by Craby. DO NOT EDIT.
#pragma once

#include "cxx.h"
#include "ffi.rs.h"
#include <condition_variable>
#include <functional>
#include <mutex>
#include <queue>
#include <thread>
#include <vector>

namespace craby {
namespace hwpjs {
namespace utils {

class ThreadPool {
private:
  bool stop;
  std::mutex mutex;
  std::condition_variable condition;
  std::queue<std::function<void()>> tasks;
  std::vector<std::thread> workers;

public:
  ThreadPool(size_t num_threads = 10) : stop(false) {
    for (size_t i = 0; i < num_threads; ++i) {
      workers.emplace_back([this] {
        while (true) {
          std::function<void()> task;

          {
            std::unique_lock<std::mutex> lock(this->mutex);
            this->condition.wait(
                lock, [this] { return this->stop || !this->tasks.empty(); });

            if (this->stop && this->tasks.empty()) {
              return;
            }

            task = std::move(this->tasks.front());
            this->tasks.pop();
          }

          task();
        }
      });
    }
  }

  template <class F> void enqueue(F &&f) {
    {
      std::unique_lock<std::mutex> lock(mutex);
      if (stop) {
        return;
      }
      tasks.emplace(std::forward<F>(f));
    }
    condition.notify_one();
  }

  void shutdown() {
    {
      std::unique_lock<std::mutex> lock(mutex);
      stop = true;
      std::queue<std::function<void()>> empty;
      std::swap(tasks, empty);
    }

    condition.notify_all();

    for (std::thread &worker : workers) {
      if (worker.joinable()) {
        worker.join();
      }
    }
  }

  ~ThreadPool() {
    shutdown();
  }
};

inline std::string errorMessage(const std::exception &err) {
  const auto* rs_err = dynamic_cast<const rust::Error*>(&err);
  return std::string(rs_err ? rs_err->what() : err.what());
}

} // namespace utils
} // namespace hwpjs
} // namespace craby
