"use strict"; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // src/index.ts var src_exports = {}; __export(src_exports, { Ryoiki: () => Ryoiki }); module.exports = __toCommonJS(src_exports); var Ryoiki = class _Ryoiki { readings; writings; readQueue; writeQueue; static async CatchError(promise) { return await promise.then((v) => [void 0, v]).catch((err) => [err]); } static IsRangeOverlap(a, b) { const [start1, end1] = a; const [start2, end2] = b; if (end1 <= start2 || end2 <= start1) { return false; } return true; } static ERR_ALREADY_EXISTS(lockId) { return new Error(`The '${lockId}' task already existing in queue or running.`); } static ERR_NOT_EXISTS(lockId) { return new Error(`The '${lockId}' task not existing in task queue.`); } static ERR_TIMEOUT(lockId, timeout) { return new Error(`The task with ID '${lockId}' failed to acquire the lock within the timeout(${timeout}ms).`); } /** * Constructs a new instance of the Ryoiki class. */ constructor() { this.readings = /* @__PURE__ */ new Map(); this.writings = /* @__PURE__ */ new Map(); this.readQueue = /* @__PURE__ */ new Map(); this.writeQueue = /* @__PURE__ */ new Map(); } /** * Creates a range based on a start value and length. * @param start - The starting value of the range. * @param length - The length of the range. * @returns A range tuple [start, start + length]. */ range(start, length) { return [start, start + length]; } rangeOverlapping(tasks, range) { return Array.from(tasks.values()).some((t) => _Ryoiki.IsRangeOverlap(t.range, range)); } isSameRange(a, b) { const [a1, a2] = a; const [b1, b2] = b; return a1 === b1 && a2 === b2; } fetchUnitAndRun(queue, workspaces) { for (const [id, unit] of queue) { if (!unit.condition()) { continue; } this._alloc(queue, workspaces, id); } } _handleOverload(args, handlers, argPatterns) { for (const [key, pattern] of Object.entries(argPatterns)) { if (this._matchArgs(args, pattern)) { return handlers[key](...args); } } throw new Error("Invalid arguments"); } _matchArgs(args, pattern) { return args.every((arg, index) => { const expectedType = pattern[index]; if (expectedType === void 0) return typeof arg === "undefined"; if (expectedType === Function) return typeof arg === "function"; if (expectedType === Number) return typeof arg === "number"; if (expectedType === Array) return Array.isArray(arg); return false; }); } _createRandomId() { const timestamp = Date.now().toString(36); const random = Math.random().toString(36).substring(2); return `${timestamp}${random}`; } _alloc(queue, workspaces, lockId) { const unit = queue.get(lockId); if (!unit) { throw _Ryoiki.ERR_NOT_EXISTS(lockId); } workspaces.set(lockId, unit); queue.delete(lockId); unit.alloc(); } _free(workspaces, lockId) { const unit = workspaces.get(lockId); if (!unit) { throw _Ryoiki.ERR_NOT_EXISTS(lockId); } workspaces.delete(lockId); unit.free(); } _lock(queue, range, timeout, task, condition) { return new Promise((resolve, reject) => { let timeoutId = null; if (timeout >= 0) { timeoutId = setTimeout(() => { reject(_Ryoiki.ERR_TIMEOUT(id, timeout)); }, timeout); } const id = this._createRandomId(); const alloc = async () => { if (timeoutId !== null) { clearTimeout(timeoutId); } const [err, v] = await _Ryoiki.CatchError(task(id)); if (err) reject(err); else resolve(v); }; const fetch = () => { this.fetchUnitAndRun(this.readQueue, this.readings); this.fetchUnitAndRun(this.writeQueue, this.writings); }; queue.set(id, { id, range, condition, alloc, free: fetch }); fetch(); }); } /** * Internal implementation of the read lock. Handles both overloads. * @template T - The return type of the task. * @param arg0 - Either a range or a task callback. * If a range is provided, the task is the second argument. * @param arg1 - The task to execute, required if a range is provided. * @param arg2 - The timeout for acquiring the lock. * If the lock cannot be acquired within this period, an error will be thrown. * If this value is not provided, no timeout will be set. * @returns A promise resolving to the result of the task execution. */ readLock(arg0, arg1, arg2) { const [range, task, timeout] = this._handleOverload( [arg0, arg1, arg2], { rangeTask: (range2, task2) => [range2, task2, -1], rangeTaskTimeout: (range2, task2, timeout2) => [range2, task2, timeout2], task: (task2) => [[-Infinity, Infinity], task2, -1], taskTimeout: (task2, timeout2) => [[-Infinity, Infinity], task2, timeout2] }, { task: [Function], taskTimeout: [Function, Number], rangeTask: [Array, Function], rangeTaskTimeout: [Array, Function, Number] } ); return this._lock( this.readQueue, range, timeout, task, () => !this.rangeOverlapping(this.writings, range) ); } /** * Internal implementation of the write lock. Handles both overloads. * @template T - The return type of the task. * @param arg0 - Either a range or a task callback. * If a range is provided, the task is the second argument. * @param arg1 - The task to execute, required if a range is provided. * @param arg2 - The timeout for acquiring the lock. * If the lock cannot be acquired within this period, an error will be thrown. * If this value is not provided, no timeout will be set. * @returns A promise resolving to the result of the task execution. */ writeLock(arg0, arg1, arg2) { const [range, task, timeout] = this._handleOverload( [arg0, arg1, arg2], { rangeTask: (range2, task2) => [range2, task2, -1], rangeTaskTimeout: (range2, task2, timeout2) => [range2, task2, timeout2], task: (task2) => [[-Infinity, Infinity], task2, -1], taskTimeout: (task2, timeout2) => [[-Infinity, Infinity], task2, timeout2] }, { task: [Function], taskTimeout: [Function, Number], rangeTask: [Array, Function], rangeTaskTimeout: [Array, Function, Number] } ); return this._lock( this.writeQueue, range, timeout, task, () => { return !this.rangeOverlapping(this.writings, range) && !this.rangeOverlapping(this.readings, range); } ); } /** * Releases a read lock by its lock ID. * @param lockId - The unique identifier for the lock to release. */ readUnlock(lockId) { this._free(this.readings, lockId); } /** * Releases a write lock by its lock ID. * @param lockId - The unique identifier for the lock to release. */ writeUnlock(lockId) { this._free(this.writings, lockId); } }; // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { Ryoiki });