@okikio/observables 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (131) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +578 -0
  3. package/esm/_dnt.polyfills.d.ts +20 -0
  4. package/esm/_dnt.polyfills.d.ts.map +1 -0
  5. package/esm/_dnt.polyfills.js +12 -0
  6. package/esm/_spec.d.ts +260 -0
  7. package/esm/_spec.d.ts.map +1 -0
  8. package/esm/_spec.js +1 -0
  9. package/esm/_types.d.ts +141 -0
  10. package/esm/_types.d.ts.map +1 -0
  11. package/esm/_types.js +20 -0
  12. package/esm/error.d.ts +331 -0
  13. package/esm/error.d.ts.map +1 -0
  14. package/esm/error.js +408 -0
  15. package/esm/events.d.ts +320 -0
  16. package/esm/events.d.ts.map +1 -0
  17. package/esm/events.js +451 -0
  18. package/esm/helpers/_types.d.ts +188 -0
  19. package/esm/helpers/_types.d.ts.map +1 -0
  20. package/esm/helpers/_types.js +1 -0
  21. package/esm/helpers/mod.d.ts +90 -0
  22. package/esm/helpers/mod.d.ts.map +1 -0
  23. package/esm/helpers/mod.js +90 -0
  24. package/esm/helpers/operations/batch.d.ts +109 -0
  25. package/esm/helpers/operations/batch.d.ts.map +1 -0
  26. package/esm/helpers/operations/batch.js +140 -0
  27. package/esm/helpers/operations/combination.d.ts +162 -0
  28. package/esm/helpers/operations/combination.d.ts.map +1 -0
  29. package/esm/helpers/operations/combination.js +350 -0
  30. package/esm/helpers/operations/conditional.d.ts +211 -0
  31. package/esm/helpers/operations/conditional.d.ts.map +1 -0
  32. package/esm/helpers/operations/conditional.js +280 -0
  33. package/esm/helpers/operations/core.d.ts +198 -0
  34. package/esm/helpers/operations/core.d.ts.map +1 -0
  35. package/esm/helpers/operations/core.js +264 -0
  36. package/esm/helpers/operations/errors.d.ts +277 -0
  37. package/esm/helpers/operations/errors.d.ts.map +1 -0
  38. package/esm/helpers/operations/errors.js +378 -0
  39. package/esm/helpers/operations/mod.d.ts +26 -0
  40. package/esm/helpers/operations/mod.d.ts.map +1 -0
  41. package/esm/helpers/operations/mod.js +25 -0
  42. package/esm/helpers/operations/timing.d.ts +206 -0
  43. package/esm/helpers/operations/timing.d.ts.map +1 -0
  44. package/esm/helpers/operations/timing.js +457 -0
  45. package/esm/helpers/operators.d.ts +520 -0
  46. package/esm/helpers/operators.d.ts.map +1 -0
  47. package/esm/helpers/operators.js +563 -0
  48. package/esm/helpers/pipe.d.ts +118 -0
  49. package/esm/helpers/pipe.d.ts.map +1 -0
  50. package/esm/helpers/pipe.js +129 -0
  51. package/esm/helpers/utils.d.ts +142 -0
  52. package/esm/helpers/utils.d.ts.map +1 -0
  53. package/esm/helpers/utils.js +193 -0
  54. package/esm/mod.d.ts +863 -0
  55. package/esm/mod.d.ts.map +1 -0
  56. package/esm/mod.js +861 -0
  57. package/esm/observable.d.ts +1610 -0
  58. package/esm/observable.d.ts.map +1 -0
  59. package/esm/observable.js +1970 -0
  60. package/esm/package.json +3 -0
  61. package/esm/queue.d.ts +201 -0
  62. package/esm/queue.d.ts.map +1 -0
  63. package/esm/queue.js +273 -0
  64. package/esm/symbol.d.ts +60 -0
  65. package/esm/symbol.d.ts.map +1 -0
  66. package/esm/symbol.js +132 -0
  67. package/package.json +96 -0
  68. package/script/_dnt.polyfills.d.ts +20 -0
  69. package/script/_dnt.polyfills.d.ts.map +1 -0
  70. package/script/_dnt.polyfills.js +13 -0
  71. package/script/_spec.d.ts +260 -0
  72. package/script/_spec.d.ts.map +1 -0
  73. package/script/_spec.js +2 -0
  74. package/script/_types.d.ts +141 -0
  75. package/script/_types.d.ts.map +1 -0
  76. package/script/_types.js +22 -0
  77. package/script/error.d.ts +331 -0
  78. package/script/error.d.ts.map +1 -0
  79. package/script/error.js +414 -0
  80. package/script/events.d.ts +320 -0
  81. package/script/events.d.ts.map +1 -0
  82. package/script/events.js +458 -0
  83. package/script/helpers/_types.d.ts +188 -0
  84. package/script/helpers/_types.d.ts.map +1 -0
  85. package/script/helpers/_types.js +2 -0
  86. package/script/helpers/mod.d.ts +90 -0
  87. package/script/helpers/mod.d.ts.map +1 -0
  88. package/script/helpers/mod.js +106 -0
  89. package/script/helpers/operations/batch.d.ts +109 -0
  90. package/script/helpers/operations/batch.d.ts.map +1 -0
  91. package/script/helpers/operations/batch.js +144 -0
  92. package/script/helpers/operations/combination.d.ts +162 -0
  93. package/script/helpers/operations/combination.d.ts.map +1 -0
  94. package/script/helpers/operations/combination.js +355 -0
  95. package/script/helpers/operations/conditional.d.ts +211 -0
  96. package/script/helpers/operations/conditional.d.ts.map +1 -0
  97. package/script/helpers/operations/conditional.js +286 -0
  98. package/script/helpers/operations/core.d.ts +198 -0
  99. package/script/helpers/operations/core.d.ts.map +1 -0
  100. package/script/helpers/operations/core.js +272 -0
  101. package/script/helpers/operations/errors.d.ts +277 -0
  102. package/script/helpers/operations/errors.d.ts.map +1 -0
  103. package/script/helpers/operations/errors.js +387 -0
  104. package/script/helpers/operations/mod.d.ts +26 -0
  105. package/script/helpers/operations/mod.d.ts.map +1 -0
  106. package/script/helpers/operations/mod.js +41 -0
  107. package/script/helpers/operations/timing.d.ts +206 -0
  108. package/script/helpers/operations/timing.d.ts.map +1 -0
  109. package/script/helpers/operations/timing.js +464 -0
  110. package/script/helpers/operators.d.ts +520 -0
  111. package/script/helpers/operators.d.ts.map +1 -0
  112. package/script/helpers/operators.js +570 -0
  113. package/script/helpers/pipe.d.ts +118 -0
  114. package/script/helpers/pipe.d.ts.map +1 -0
  115. package/script/helpers/pipe.js +132 -0
  116. package/script/helpers/utils.d.ts +142 -0
  117. package/script/helpers/utils.d.ts.map +1 -0
  118. package/script/helpers/utils.js +200 -0
  119. package/script/mod.d.ts +863 -0
  120. package/script/mod.d.ts.map +1 -0
  121. package/script/mod.js +877 -0
  122. package/script/observable.d.ts +1610 -0
  123. package/script/observable.d.ts.map +1 -0
  124. package/script/observable.js +1984 -0
  125. package/script/package.json +3 -0
  126. package/script/queue.d.ts +201 -0
  127. package/script/queue.d.ts.map +1 -0
  128. package/script/queue.js +286 -0
  129. package/script/symbol.d.ts +60 -0
  130. package/script/symbol.d.ts.map +1 -0
  131. package/script/symbol.js +135 -0
@@ -0,0 +1,3 @@
1
+ {
2
+ "type": "module"
3
+ }
package/esm/queue.d.ts ADDED
@@ -0,0 +1,201 @@
1
+ /**
2
+ * A lightweight circular-buffer queue for the library's hot paths.
3
+ *
4
+ * This entrypoint exposes the small FIFO data structure that backs replay,
5
+ * buffering, and event fan-out inside the Observable runtime. It keeps
6
+ * enqueue/dequeue work O(1) by moving `head` and `tail` pointers around a fixed
7
+ * array instead of repeatedly calling `Array.shift()`, which has to move every
8
+ * remaining element one slot to the left.
9
+ *
10
+ * Use this module when you need predictable queue performance and explicit
11
+ * capacity control. It is especially useful for buffers that grow and shrink
12
+ * frequently, where repeated array reindexing would turn steady traffic into an
13
+ * unnecessary O(n) cost.
14
+ *
15
+ * @example
16
+ * ```
17
+ * import { createQueue, enqueue, dequeue, peek } from './queue.ts';
18
+ *
19
+ * const taskQueue = createQueue<string>(100); // capacity of 100
20
+ * enqueue(taskQueue, 'process-order-123'); // add task
21
+ * enqueue(taskQueue, 'send-email-456'); // add another
22
+ *
23
+ * console.log(peek(taskQueue)); // 'process-order-123' (doesn't remove)
24
+ * console.log(dequeue(taskQueue)); // 'process-order-123' (removes and returns)
25
+ *
26
+ * clear(taskQueue); // empty the queue instantly
27
+ * ```
28
+ *
29
+ * @module
30
+ */
31
+ /**
32
+ * Represents a circular buffer-based queue for efficient FIFO operations.
33
+ *
34
+ * @template T - The type of elements stored in the queue
35
+ */
36
+ import "./_dnt.polyfills.js";
37
+ export interface Queue<T> {
38
+ /** The backing array that holds queue elements */
39
+ items: T[];
40
+ /** Index pointing to the front element (next to dequeue) */
41
+ head: number;
42
+ /** Index pointing to where the next element will be added */
43
+ tail: number;
44
+ /** Current number of elements in the queue */
45
+ size: number;
46
+ /** Maximum capacity of the queue */
47
+ capacity: number;
48
+ }
49
+ /**
50
+ * Creates a new empty queue with the specified capacity.
51
+ *
52
+ * The queue uses a circular buffer internally, which means operations
53
+ * like enqueue and dequeue run in constant O(1) time regardless of
54
+ * queue size.
55
+ *
56
+ * @param capacity - Maximum number of elements the queue can hold (default: 1000)
57
+ * @returns A new empty queue ready for use
58
+ *
59
+ * @example
60
+ * ```
61
+ * const messageQueue = createQueue<string>(50); // for messages
62
+ * const numberQueue = createQueue<number>(); // uses default capacity
63
+ * ```
64
+ */
65
+ export declare function createQueue<T>(capacity?: number): Queue<T>;
66
+ /**
67
+ * Adds an element to the back of the queue (FIFO: last in, first served).
68
+ * Runs in O(1) constant time.
69
+ *
70
+ * @param queue - The target queue
71
+ * @param item - Element to add to the queue
72
+ * @throws Error if the queue is at capacity
73
+ *
74
+ * @example
75
+ * ```
76
+ * enqueue(userQueue, { id: 123, name: 'Alice' });
77
+ * enqueue(userQueue, { id: 124, name: 'Bob' });
78
+ * ```
79
+ */
80
+ export declare function enqueue<T>(queue: Queue<T>, item: T): void;
81
+ /**
82
+ * Removes and returns the front element from the queue (FIFO: first in, first out).
83
+ * Runs in O(1) constant time.
84
+ *
85
+ * @param queue - The target queue
86
+ * @returns The front element, or undefined if queue is empty
87
+ *
88
+ * @example
89
+ * ```
90
+ * const nextTask = dequeue(taskQueue);
91
+ * if (nextTask) {
92
+ * console.log('Processing:', nextTask);
93
+ * }
94
+ * ```
95
+ */
96
+ export declare function dequeue<T>(queue: Queue<T>): T | undefined;
97
+ /**
98
+ * Returns the front element without removing it from the queue.
99
+ * Useful for checking what's next without consuming it.
100
+ * Runs in O(1) constant time.
101
+ *
102
+ * @param queue - The target queue
103
+ * @returns The front element, or undefined if queue is empty
104
+ *
105
+ * @example
106
+ * ```
107
+ * const nextInLine = peek(queue);
108
+ * if (nextInLine?.priority === 'urgent') {
109
+ * // handle urgent task immediately
110
+ * dequeue(queue);
111
+ * }
112
+ * ```
113
+ */
114
+ export declare function peek<T>(queue: Queue<T>): T | undefined;
115
+ /**
116
+ * Checks if the queue contains no elements.
117
+ *
118
+ * @param queue - The target queue
119
+ * @returns true if the queue is empty, false otherwise
120
+ */
121
+ export declare function isEmpty<T>(queue: Queue<T>): boolean;
122
+ /**
123
+ * Checks if the queue has reached its maximum capacity.
124
+ *
125
+ * @param queue - The target queue
126
+ * @returns true if the queue is full, false otherwise
127
+ */
128
+ export declare function isFull<T>(queue: Queue<T>): boolean;
129
+ /**
130
+ * Returns the current number of elements in the queue.
131
+ *
132
+ * @param queue - The target queue
133
+ * @returns Current queue size (0 to capacity)
134
+ */
135
+ export declare function getSize<T>(queue: Queue<T>): number;
136
+ /**
137
+ * Returns how many more elements can be added before hitting capacity.
138
+ *
139
+ * @param queue - The target queue
140
+ * @returns Number of available slots
141
+ *
142
+ * @example
143
+ * ```
144
+ * if (remainingSpace(queue) < 10) {
145
+ * console.warn('Queue nearly full, consider processing items');
146
+ * }
147
+ * ```
148
+ */
149
+ export declare function remainingSpace<T>(queue: Queue<T>): number;
150
+ /**
151
+ * Empties the queue instantly using the `.length = 0` optimization[87][90].
152
+ * This immediately releases all object references for garbage collection,
153
+ * making it much faster than dequeuing items one by one.
154
+ *
155
+ * Runs in O(1) constant time regardless of queue size.
156
+ *
157
+ * @param queue - The target queue
158
+ *
159
+ * @example
160
+ * ```
161
+ * // Instead of: while (!isEmpty(queue)) dequeue(queue); // O(n)
162
+ * clear(queue); // O(1) - much faster!
163
+ * ```
164
+ */
165
+ export declare function clear<T>(queue: Queue<T>): void;
166
+ /**
167
+ * Creates a new array containing all queue elements in order (front to back).
168
+ * Useful for debugging, logging, or when you need array methods.
169
+ *
170
+ * Note: This is O(n) operation - use sparingly in performance-critical code.
171
+ *
172
+ * @param queue - The source queue
173
+ * @returns New array with queue elements in FIFO order
174
+ *
175
+ * @example
176
+ * ```
177
+ * const queueSnapshot = toArray(queue);
178
+ * console.log('Current queue:', queueSnapshot.join(' -> '));
179
+ *
180
+ * // Process without modifying original queue
181
+ * const urgentItems = queueSnapshot.filter(item => item.priority === 'urgent');
182
+ * ```
183
+ */
184
+ export declare function toArray<T>(queue: Queue<T>): T[];
185
+ /**
186
+ * Applies a function to each element in the queue without modifying it.
187
+ * Elements are visited in FIFO order (front to back).
188
+ *
189
+ * @param queue - The target queue
190
+ * @param callback - Function to call for each element
191
+ *
192
+ * @example
193
+ * ```
194
+ * // Log all pending tasks
195
+ * forEach(taskQueue, (task, index) => {
196
+ * console.log(`Task ${index + 1}: ${task.description}`);
197
+ * });
198
+ * ```
199
+ */
200
+ export declare function forEach<T>(queue: Queue<T>, callback: (item: T, index: number) => void): void;
201
+ //# sourceMappingURL=queue.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"queue.d.ts","sourceRoot":"","sources":["../src/queue.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAMH;;;;GAIG;AACH,OAAO,qBAAqB,CAAC;AAE7B,MAAM,WAAW,KAAK,CAAC,CAAC;IACtB,kDAAkD;IAClD,KAAK,EAAE,CAAC,EAAE,CAAC;IACX,4DAA4D;IAC5D,IAAI,EAAE,MAAM,CAAC;IACb,6DAA6D;IAC7D,IAAI,EAAE,MAAM,CAAC;IACb,8CAA8C;IAC9C,IAAI,EAAE,MAAM,CAAC;IACb,oCAAoC;IACpC,QAAQ,EAAE,MAAM,CAAC;CAClB;AAkBD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,WAAW,CAAC,CAAC,EAAE,QAAQ,GAAE,MAAa,GAAG,KAAK,CAAC,CAAC,CAAC,CAQhE;AAMD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,OAAO,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,GAAG,IAAI,CAUzD;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,OAAO,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,SAAS,CAWzD;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,IAAI,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,SAAS,CAEtD;AAMD;;;;;GAKG;AACH,wBAAgB,OAAO,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,GAAG,OAAO,CAEnD;AAED;;;;;GAKG;AACH,wBAAgB,MAAM,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,GAAG,OAAO,CAElD;AAED;;;;;GAKG;AACH,wBAAgB,OAAO,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,GAAG,MAAM,CAElD;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,cAAc,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,GAAG,MAAM,CAEzD;AAMD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,KAAK,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,GAAG,IAAI,CAS9C;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,OAAO,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAc/C;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,OAAO,CAAC,CAAC,EACvB,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,EACf,QAAQ,EAAE,CAAC,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,GACzC,IAAI,CAON"}
package/esm/queue.js ADDED
@@ -0,0 +1,273 @@
1
+ /**
2
+ * A lightweight circular-buffer queue for the library's hot paths.
3
+ *
4
+ * This entrypoint exposes the small FIFO data structure that backs replay,
5
+ * buffering, and event fan-out inside the Observable runtime. It keeps
6
+ * enqueue/dequeue work O(1) by moving `head` and `tail` pointers around a fixed
7
+ * array instead of repeatedly calling `Array.shift()`, which has to move every
8
+ * remaining element one slot to the left.
9
+ *
10
+ * Use this module when you need predictable queue performance and explicit
11
+ * capacity control. It is especially useful for buffers that grow and shrink
12
+ * frequently, where repeated array reindexing would turn steady traffic into an
13
+ * unnecessary O(n) cost.
14
+ *
15
+ * @example
16
+ * ```
17
+ * import { createQueue, enqueue, dequeue, peek } from './queue.ts';
18
+ *
19
+ * const taskQueue = createQueue<string>(100); // capacity of 100
20
+ * enqueue(taskQueue, 'process-order-123'); // add task
21
+ * enqueue(taskQueue, 'send-email-456'); // add another
22
+ *
23
+ * console.log(peek(taskQueue)); // 'process-order-123' (doesn't remove)
24
+ * console.log(dequeue(taskQueue)); // 'process-order-123' (removes and returns)
25
+ *
26
+ * clear(taskQueue); // empty the queue instantly
27
+ * ```
28
+ *
29
+ * @module
30
+ */
31
+ ///////////////////////
32
+ // Core Data Types //
33
+ ///////////////////////
34
+ /**
35
+ * Represents a circular buffer-based queue for efficient FIFO operations.
36
+ *
37
+ * @template T - The type of elements stored in the queue
38
+ */
39
+ import "./_dnt.polyfills.js";
40
+ /**
41
+ * Advances a circular-buffer index by one slot and wraps back to `0` at the end.
42
+ *
43
+ * This keeps the same O(1) behavior as `% capacity`, but avoids paying modulo
44
+ * cost for arbitrary capacities in the queue hot path. It is private because
45
+ * it only exists to speed up internal queue pointer movement.
46
+ */
47
+ function advanceIndex(index, capacity) {
48
+ const next = index + 1;
49
+ return next === capacity ? 0 : next;
50
+ }
51
+ ////////////////////////////
52
+ // Factory & Core Setup //
53
+ ////////////////////////////
54
+ /**
55
+ * Creates a new empty queue with the specified capacity.
56
+ *
57
+ * The queue uses a circular buffer internally, which means operations
58
+ * like enqueue and dequeue run in constant O(1) time regardless of
59
+ * queue size.
60
+ *
61
+ * @param capacity - Maximum number of elements the queue can hold (default: 1000)
62
+ * @returns A new empty queue ready for use
63
+ *
64
+ * @example
65
+ * ```
66
+ * const messageQueue = createQueue<string>(50); // for messages
67
+ * const numberQueue = createQueue<number>(); // uses default capacity
68
+ * ```
69
+ */
70
+ export function createQueue(capacity = 1000) {
71
+ return {
72
+ items: new Array(capacity),
73
+ head: 0,
74
+ tail: 0,
75
+ size: 0,
76
+ capacity,
77
+ };
78
+ }
79
+ /////////////////////////
80
+ // Core Queue Operations //
81
+ /////////////////////////
82
+ /**
83
+ * Adds an element to the back of the queue (FIFO: last in, first served).
84
+ * Runs in O(1) constant time.
85
+ *
86
+ * @param queue - The target queue
87
+ * @param item - Element to add to the queue
88
+ * @throws Error if the queue is at capacity
89
+ *
90
+ * @example
91
+ * ```
92
+ * enqueue(userQueue, { id: 123, name: 'Alice' });
93
+ * enqueue(userQueue, { id: 124, name: 'Bob' });
94
+ * ```
95
+ */
96
+ export function enqueue(queue, item) {
97
+ if (isFull(queue)) {
98
+ throw new Error(`Queue overflow: cannot add item, capacity ${queue.capacity} reached`);
99
+ }
100
+ queue.items[queue.tail] = item;
101
+ queue.tail = advanceIndex(queue.tail, queue.capacity);
102
+ queue.size++;
103
+ }
104
+ /**
105
+ * Removes and returns the front element from the queue (FIFO: first in, first out).
106
+ * Runs in O(1) constant time.
107
+ *
108
+ * @param queue - The target queue
109
+ * @returns The front element, or undefined if queue is empty
110
+ *
111
+ * @example
112
+ * ```
113
+ * const nextTask = dequeue(taskQueue);
114
+ * if (nextTask) {
115
+ * console.log('Processing:', nextTask);
116
+ * }
117
+ * ```
118
+ */
119
+ export function dequeue(queue) {
120
+ if (isEmpty(queue)) {
121
+ return undefined;
122
+ }
123
+ const item = queue.items[queue.head];
124
+ queue.items[queue.head] = undefined; // help garbage collector
125
+ queue.head = advanceIndex(queue.head, queue.capacity);
126
+ queue.size--;
127
+ return item;
128
+ }
129
+ /**
130
+ * Returns the front element without removing it from the queue.
131
+ * Useful for checking what's next without consuming it.
132
+ * Runs in O(1) constant time.
133
+ *
134
+ * @param queue - The target queue
135
+ * @returns The front element, or undefined if queue is empty
136
+ *
137
+ * @example
138
+ * ```
139
+ * const nextInLine = peek(queue);
140
+ * if (nextInLine?.priority === 'urgent') {
141
+ * // handle urgent task immediately
142
+ * dequeue(queue);
143
+ * }
144
+ * ```
145
+ */
146
+ export function peek(queue) {
147
+ return isEmpty(queue) ? undefined : queue.items[queue.head];
148
+ }
149
+ ////////////////////////////////
150
+ // Utility & Status Functions //
151
+ ////////////////////////////////
152
+ /**
153
+ * Checks if the queue contains no elements.
154
+ *
155
+ * @param queue - The target queue
156
+ * @returns true if the queue is empty, false otherwise
157
+ */
158
+ export function isEmpty(queue) {
159
+ return queue.size === 0;
160
+ }
161
+ /**
162
+ * Checks if the queue has reached its maximum capacity.
163
+ *
164
+ * @param queue - The target queue
165
+ * @returns true if the queue is full, false otherwise
166
+ */
167
+ export function isFull(queue) {
168
+ return queue.size >= queue.capacity;
169
+ }
170
+ /**
171
+ * Returns the current number of elements in the queue.
172
+ *
173
+ * @param queue - The target queue
174
+ * @returns Current queue size (0 to capacity)
175
+ */
176
+ export function getSize(queue) {
177
+ return queue.size;
178
+ }
179
+ /**
180
+ * Returns how many more elements can be added before hitting capacity.
181
+ *
182
+ * @param queue - The target queue
183
+ * @returns Number of available slots
184
+ *
185
+ * @example
186
+ * ```
187
+ * if (remainingSpace(queue) < 10) {
188
+ * console.warn('Queue nearly full, consider processing items');
189
+ * }
190
+ * ```
191
+ */
192
+ export function remainingSpace(queue) {
193
+ return queue.capacity - queue.size;
194
+ }
195
+ /////////////////////////////
196
+ // Advanced Utility Functions //
197
+ /////////////////////////////
198
+ /**
199
+ * Empties the queue instantly using the `.length = 0` optimization[87][90].
200
+ * This immediately releases all object references for garbage collection,
201
+ * making it much faster than dequeuing items one by one.
202
+ *
203
+ * Runs in O(1) constant time regardless of queue size.
204
+ *
205
+ * @param queue - The target queue
206
+ *
207
+ * @example
208
+ * ```
209
+ * // Instead of: while (!isEmpty(queue)) dequeue(queue); // O(n)
210
+ * clear(queue); // O(1) - much faster!
211
+ * ```
212
+ */
213
+ export function clear(queue) {
214
+ // Fast array truncation - instantly releases references for GC[87][90]
215
+ queue.items.length = 0;
216
+ queue.items.length = queue.capacity; // restore original capacity
217
+ // Reset pointers
218
+ queue.head = 0;
219
+ queue.tail = 0;
220
+ queue.size = 0;
221
+ }
222
+ /**
223
+ * Creates a new array containing all queue elements in order (front to back).
224
+ * Useful for debugging, logging, or when you need array methods.
225
+ *
226
+ * Note: This is O(n) operation - use sparingly in performance-critical code.
227
+ *
228
+ * @param queue - The source queue
229
+ * @returns New array with queue elements in FIFO order
230
+ *
231
+ * @example
232
+ * ```
233
+ * const queueSnapshot = toArray(queue);
234
+ * console.log('Current queue:', queueSnapshot.join(' -> '));
235
+ *
236
+ * // Process without modifying original queue
237
+ * const urgentItems = queueSnapshot.filter(item => item.priority === 'urgent');
238
+ * ```
239
+ */
240
+ export function toArray(queue) {
241
+ if (isEmpty(queue)) {
242
+ return [];
243
+ }
244
+ const result = new Array(queue.size);
245
+ let index = queue.head;
246
+ for (let i = 0; i < queue.size; i++) {
247
+ result[i] = queue.items[index];
248
+ index = advanceIndex(index, queue.capacity);
249
+ }
250
+ return result;
251
+ }
252
+ /**
253
+ * Applies a function to each element in the queue without modifying it.
254
+ * Elements are visited in FIFO order (front to back).
255
+ *
256
+ * @param queue - The target queue
257
+ * @param callback - Function to call for each element
258
+ *
259
+ * @example
260
+ * ```
261
+ * // Log all pending tasks
262
+ * forEach(taskQueue, (task, index) => {
263
+ * console.log(`Task ${index + 1}: ${task.description}`);
264
+ * });
265
+ * ```
266
+ */
267
+ export function forEach(queue, callback) {
268
+ let index = queue.head;
269
+ for (let i = 0; i < queue.size; i++) {
270
+ callback(queue.items[index], i);
271
+ index = advanceIndex(index, queue.capacity);
272
+ }
273
+ }
@@ -0,0 +1,60 @@
1
+ /**
2
+ * > Inspired by https://jsr.io/@nick/dispose/1.1.0/symbol.ts
3
+ *
4
+ * Extensions to the global Symbol constructor for interoperability with
5
+ * Observable.
6
+ *
7
+ * This interface extends the standard Symbol constructor with well-known
8
+ * symbols needed for Observable interoperability and resource cleanup:
9
+ *
10
+ * 1. `Symbol.observable`: For Observable interoperability (TC39 proposal)
11
+ *
12
+ * These symbols enable our implementation to work with:
13
+ * - Other Observable libraries via Symbol.observable
14
+ *
15
+ * @example
16
+ * ```ts
17
+ * // Using Symbol.observable for interop
18
+ * const myObservable = {
19
+ * [Symbol.observable]() {
20
+ * return new Observable(observer => {
21
+ * observer.next('Hello');
22
+ * observer.complete();
23
+ * });
24
+ * }
25
+ * };
26
+ * ```
27
+ *
28
+ * @module
29
+ */
30
+ export interface SymbolConstructor extends Omit<typeof globalThis.Symbol, "observable"> {
31
+ /**
32
+ * Well-known symbol for Observable interoperability.
33
+ *
34
+ * This symbol allows any object to define how it converts to an Observable.
35
+ * Objects with a `[Symbol.observable]()` method can be passed directly to
36
+ * `Observable.from()` and will be properly converted.
37
+ *
38
+ * This is analogous to how `Symbol.iterator` enables iteration interop.
39
+ *
40
+ * @see {@link https://github.com/tc39/proposal-observable | TC39 Observable proposal}
41
+ */
42
+ readonly observable: unique symbol;
43
+ }
44
+ /**
45
+ * Provides a cross-platform Symbol implementation with Observable
46
+ * and resource management symbols.
47
+ *
48
+ * This implementation:
49
+ * 1. Uses the native Symbol if available
50
+ * 2. Falls back to a polyfill if Symbol is not supported
51
+ * 3. Adds our special symbols if they don't exist natively
52
+ *
53
+ * The polyfill is lightweight and provides basic Symbol functionality
54
+ * for environments that don't support it natively.
55
+ *
56
+ * Note: The polyfill does not implement the full Symbol specification
57
+ * and is intended only for basic interoperability in legacy environments.
58
+ */
59
+ export declare const Symbol: SymbolConstructor;
60
+ //# sourceMappingURL=symbol.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"symbol.d.ts","sourceRoot":"","sources":["../src/symbol.ts"],"names":[],"mappings":"AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,MAAM,WAAW,iBACf,SAAQ,IAAI,CAAC,OAAO,UAAU,CAAC,MAAM,EAAE,YAAY,CAAC;IACpD;;;;;;;;;;OAUG;IACH,QAAQ,CAAC,UAAU,EAAE,OAAO,MAAM,CAAC;CACpC;AAED;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,MAAM,EAAE,iBAIiB,CAAC"}
package/esm/symbol.js ADDED
@@ -0,0 +1,132 @@
1
+ /**
2
+ * Provides a cross-platform Symbol implementation with Observable
3
+ * and resource management symbols.
4
+ *
5
+ * This implementation:
6
+ * 1. Uses the native Symbol if available
7
+ * 2. Falls back to a polyfill if Symbol is not supported
8
+ * 3. Adds our special symbols if they don't exist natively
9
+ *
10
+ * The polyfill is lightweight and provides basic Symbol functionality
11
+ * for environments that don't support it natively.
12
+ *
13
+ * Note: The polyfill does not implement the full Symbol specification
14
+ * and is intended only for basic interoperability in legacy environments.
15
+ */
16
+ export const Symbol = (globalThis.Symbol ??
17
+ ((description) => ({
18
+ description,
19
+ toString: () => `Symbol(${description})`,
20
+ })));
21
+ /**
22
+ * Adds Symbol.dispose if it doesn't exist natively.
23
+ *
24
+ * Symbol.dispose enables automatic resource cleanup using the `using` declaration.
25
+ * When a variable declared with `using` goes out of scope, its `[Symbol.dispose]()`
26
+ * method is called automatically, ensuring cleanup happens even if errors occur.
27
+ *
28
+ * @example Basic resource cleanup with using
29
+ * ```ts
30
+ * import { Observable } from './observable.ts';
31
+ *
32
+ * {
33
+ * using subscription = Observable.of(1, 2, 3).subscribe({
34
+ * next: (val) => console.log('Value:', val)
35
+ * });
36
+ *
37
+ * // Use the subscription here
38
+ * // ...
39
+ * } // subscription.unsubscribe() called automatically at block end
40
+ * ```
41
+ *
42
+ * @example Automatic cleanup on error
43
+ * ```ts
44
+ * import { Observable } from './observable.ts';
45
+ *
46
+ * function processData() {
47
+ * using sub = Observable.from(dataStream).subscribe({
48
+ * next: (data) => processItem(data)
49
+ * });
50
+ *
51
+ * if (invalidCondition) {
52
+ * throw new Error('Processing failed');
53
+ * }
54
+ * // sub.unsubscribe() called even if error thrown
55
+ * }
56
+ * ```
57
+ */
58
+ if (typeof globalThis.Symbol === "function" &&
59
+ typeof Symbol.dispose !== "symbol") {
60
+ Reflect.defineProperty(Symbol, "dispose", {
61
+ // deno-lint-ignore no-explicit-any
62
+ value: Symbol("Symbol.dispose"),
63
+ enumerable: false,
64
+ configurable: false,
65
+ writable: false,
66
+ });
67
+ }
68
+ /**
69
+ * Adds Symbol.asyncDispose if it doesn't exist natively.
70
+ *
71
+ * Symbol.asyncDispose enables automatic async resource cleanup using `await using`.
72
+ * When a variable declared with `await using` goes out of scope, its
73
+ * `[Symbol.asyncDispose]()` method is called and awaited automatically,
74
+ * ensuring async cleanup (like closing connections) happens safely.
75
+ *
76
+ * @example Async resource cleanup with await using
77
+ * ```ts
78
+ * import { Observable } from './observable.ts';
79
+ *
80
+ * async function streamData() {
81
+ * await using sub = Observable.of(1, 2, 3).subscribe({
82
+ * next: async (data) => await saveData(data)
83
+ * });
84
+ *
85
+ * // Use the subscription here
86
+ * // ...
87
+ * } // sub.unsubscribe() (or async dispose) awaited automatically at block end
88
+ * ```
89
+ *
90
+ * @example Guaranteed async cleanup on error
91
+ * ```ts
92
+ * import { Observable } from './observable.ts';
93
+ *
94
+ * async function fetchAndProcess() {
95
+ * await using sub = Observable.from(apiStream).subscribe({
96
+ * next: async (item) => await processAsync(item)
97
+ * });
98
+ *
99
+ * if (errorCondition) {
100
+ * throw new Error('Failed');
101
+ * }
102
+ * // Async cleanup guaranteed even if error thrown
103
+ * }
104
+ * ```
105
+ */
106
+ if (typeof globalThis.Symbol === "function" &&
107
+ typeof Symbol.asyncDispose !== "symbol") {
108
+ Reflect.defineProperty(Symbol, "asyncDispose", {
109
+ // deno-lint-ignore no-explicit-any
110
+ value: Symbol("Symbol.asyncDispose"),
111
+ enumerable: false,
112
+ configurable: false,
113
+ writable: false,
114
+ });
115
+ }
116
+ /**
117
+ * Adds Symbol.observable if it doesn't exist natively.
118
+ *
119
+ * This ensures Symbol.observable is available for Observable
120
+ * interoperability, even in environments that don't support
121
+ * it natively.
122
+ */
123
+ if (typeof globalThis.Symbol === "function" &&
124
+ typeof Symbol.observable !== "symbol") {
125
+ Reflect.defineProperty(Symbol, "observable", {
126
+ // deno-lint-ignore no-explicit-any
127
+ value: Symbol("Symbol.observable"),
128
+ enumerable: false,
129
+ configurable: false,
130
+ writable: false,
131
+ });
132
+ }