///|
#external
type WebNNProgramScheduler
///|
extern "js" fn new_program_scheduler(pool_size : Int) -> WebNNProgramScheduler =
#| (poolSize) => {
#| const scheduler = {
#| poolSize,
#| available: Array.from({ length: poolSize }, (_, index) => index),
#| jobs: [],
#| active: 0,
#| maximumConcurrency: 0,
#| closed: false,
#| disposer: undefined,
#| disposed: false,
#| };
#| const disposeIfReady = () => {
#| if (scheduler.closed && scheduler.active === 0 &&
#| scheduler.jobs.length === 0 && !scheduler.disposed) {
#| scheduler.disposed = true;
#| scheduler.disposer();
#| }
#| };
#| scheduler.pump = () => {
#| while (scheduler.available.length > 0 && scheduler.jobs.length > 0) {
#| const slot = scheduler.available.shift();
#| const job = scheduler.jobs.shift();
#| scheduler.active += 1;
#| scheduler.maximumConcurrency = Math.max(
#| scheduler.maximumConcurrency,
#| scheduler.active,
#| );
#| Promise.resolve()
#| .then(() => job.operation(slot))
#| .then(job.resolve, job.reject)
#| .finally(() => {
#| scheduler.active -= 1;
#| scheduler.available.push(slot);
#| scheduler.pump();
#| disposeIfReady();
#| });
#| }
#| disposeIfReady();
#| };
#| return scheduler;
#| }
///|
extern "js" fn enqueue_program_run(
scheduler : WebNNProgramScheduler,
operation : (Int) -> @js.Promise[Array[WebNNNamedValues]],
) -> @js.Promise[Array[WebNNNamedValues]] =
#| (scheduler, operation) => {
#| if (scheduler.closed) {
#| return Promise.reject(new Error("WebNN program has been destroyed"));
#| }
#| return new Promise((resolve, reject) => {
#| scheduler.jobs.push({ operation, resolve, reject });
#| scheduler.pump();
#| });
#| }
///|
extern "js" fn enqueue_program_destroy(
scheduler : WebNNProgramScheduler,
operation : () -> Unit,
) -> Unit =
#| (scheduler, operation) => {
#| if (scheduler.closed) return;
#| scheduler.closed = true;
#| scheduler.disposer = operation;
#| scheduler.pump();
#| }
///|
extern "js" fn program_maximum_concurrency(
scheduler : WebNNProgramScheduler,
) -> Int =
#| (scheduler) => scheduler.maximumConcurrency