ciorent 0.2.1 → 0.3.0

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.
package/README.md CHANGED
@@ -106,42 +106,69 @@ task1();
106
106
  task2();
107
107
  ```
108
108
 
109
- ### Channel
110
- Channel is a synchronization primitive via message passing. A message may be sent over a channel, and another process is able to receive messages sent over a channel it has a reference to.
109
+ ### Pubsub
110
+ A fast, simple publish-subscribe API.
111
111
 
112
112
  ```ts
113
- import * as channel from 'ciorent/channel';
113
+ import * as topic from 'ciorent/topic';
114
114
  import * as co from 'ciorent';
115
115
 
116
- const c = channel.init<number>();
116
+ const messages = topic.init<number>();
117
117
 
118
- const run = async () => {
119
- for (let i = 0; i < 5; i++) {
118
+ // A task that publish messages
119
+ const publisher = async () => {
120
+ for (let i = 0; i < 3; i++) {
120
121
  await co.sleep(100);
121
- channel.send(c, i);
122
- console.log('Sent', i);
122
+ topic.publish(messages, i);
123
123
  }
124
124
 
125
- // Resolve all waiting promises with `undefined`
126
- // This is a way to tell the reciever to not listen to more data
127
- channel.flush(c);
128
- };
125
+ // Resolve all waiting promises
126
+ // And clear the value queue
127
+ topic.flush(messages);
128
+ }
129
+
130
+ // Spawn 3 tasks that recieve messages
131
+ co.spawn(3, async (id: number) => {
132
+ const sub = topic.subscribe(messages);
129
133
 
130
- const log = async () => {
131
134
  while (true) {
132
- // Wait until a value is sent to the channel
133
- const x = await channel.recieve(c);
135
+ // Block until the value is sent
136
+ const x = await topic.recieve(sub);
134
137
  if (x == null) break;
138
+ console.log(`Task ${id} recieved: ${x}`);
139
+ }
140
+ });
135
141
 
136
- console.log('Recieved', x);
137
- };
138
- }
142
+ publisher();
143
+ ```
139
144
 
140
- log();
141
- run();
145
+ ### Semaphore
146
+ Semaphore is a concurrency primitive used to control access to a common resource by multiple processes.
142
147
 
143
- // This runs first
144
- console.log('Starting...');
148
+ ```ts
149
+ import * as semaphore from 'ciorent/semaphore';
150
+ import * as co from 'ciorent';
151
+
152
+ // Only allow 2 task to run concurrently
153
+ const sem = semaphore.init(2);
154
+
155
+ const task = async (id: number) => {
156
+ // Acquire the semaphore or wait for the semaphore to be available
157
+ await semaphore.acquire(sem);
158
+
159
+ console.log('Task', id, 'started');
160
+
161
+ // Let the main thread schedules other tasks
162
+ for (let i = 1; i <= 5; i++) await co.pause;
163
+
164
+ console.log('Task', id, 'end');
165
+
166
+ // Release the semaphore
167
+ semaphore.release(sem);
168
+ }
169
+
170
+ // Try to run 5 tasks concurrently
171
+ co.spawn(5, task);
145
172
  ```
146
173
 
147
174
  ### Latch
@@ -171,69 +198,42 @@ task();
171
198
  prepare();
172
199
  ```
173
200
 
174
- ### Semaphore
175
- Semaphore is a concurrency primitive used to control access to a common resource by multiple processes.
176
-
177
- ```ts
178
- import * as semaphore from 'ciorent/semaphore';
179
- import * as co from 'ciorent';
180
-
181
- // Only allow 2 task to run concurrently
182
- const sem = semaphore.init(2);
183
-
184
- const task = async (id: number) => {
185
- // Acquire the semaphore or wait for the semaphore to be available
186
- await semaphore.pause(sem);
187
-
188
- console.log('Task', id, 'started');
189
-
190
- // Let the main thread schedules other tasks
191
- for (let i = 1; i <= 5; i++) await co.pause;
192
-
193
- console.log('Task', id, 'end');
194
-
195
- // Release the semaphore
196
- semaphore.signal(sem);
197
- }
198
-
199
- // Try to run 5 tasks concurrently
200
- co.spawn(5, task);
201
- ```
202
-
203
- ### Pubsub
204
- A fast, simple publish-subscribe API.
201
+ ### Channel
202
+ Channel is a synchronization primitive via message passing. A message may be sent over a channel, and another process is able to receive messages sent over a channel it has a reference to.
205
203
 
206
204
  ```ts
207
- import * as topic from 'ciorent/topic';
205
+ import * as channel from 'ciorent/channel';
208
206
  import * as co from 'ciorent';
209
207
 
210
- const messages = topic.init<number>();
208
+ const c = channel.init<number>();
211
209
 
212
- // A task that publish messages
213
- const publisher = async () => {
214
- for (let i = 0; i < 3; i++) {
210
+ const run = async () => {
211
+ for (let i = 0; i < 5; i++) {
215
212
  await co.sleep(100);
216
- topic.publish(messages, i);
213
+ channel.send(c, i);
214
+ console.log('Sent', i);
217
215
  }
218
216
 
219
- // Resolve all waiting promises
220
- // And clear the value queue
221
- topic.flush(messages);
222
- }
223
-
224
- // Spawn 3 tasks that recieve messages
225
- co.spawn(3, async (id: number) => {
226
- const sub = topic.subscribe(messages);
217
+ // Resolve all waiting promises with `undefined`
218
+ // This is a way to tell the reciever to not listen to more data
219
+ channel.flush(c);
220
+ };
227
221
 
222
+ const log = async () => {
228
223
  while (true) {
229
- // Block until the value is sent
230
- const x = await topic.recieve(sub);
224
+ // Wait until a value is sent to the channel
225
+ const x = await channel.recieve(c);
231
226
  if (x == null) break;
232
- console.log(`Task ${id} recieved: ${x}`);
233
- }
234
- });
235
227
 
236
- publisher();
228
+ console.log('Recieved', x);
229
+ };
230
+ }
231
+
232
+ log();
233
+ run();
234
+
235
+ // This runs first
236
+ console.log('Starting...');
237
237
  ```
238
238
 
239
239
  ### Fibers
@@ -243,8 +243,11 @@ Virtual threads with more controlled execution.
243
243
  import * as co from 'ciorent';
244
244
  import * as fiber from 'ciorent/fiber';
245
245
 
246
+ const logTime = (label: string) => console.log(label + ':', Math.floor(performance.now()) + 'ms');
247
+
246
248
  const f1 = fiber.fn(function* () {
247
249
  // Wait for a promise
250
+ console.log('Fiber 1 waiting: 1s');
248
251
  yield co.sleep(1000);
249
252
 
250
253
  // Wait for a promise and return its result
@@ -255,26 +258,21 @@ const f1 = fiber.fn(function* () {
255
258
  });
256
259
 
257
260
  {
261
+ // Start the fiber process on next event loop cycle
258
262
  const main = fiber.spawn(function* (proc) {
259
263
  // Start f1, wait for the process to complete and get the result
264
+ console.log('Fiber 2: joins fiber 1');
260
265
  const res = yield* fiber.join(fiber.spawn(f1));
261
266
  console.log('Fiber 2 recieved:', res);
262
267
 
263
268
  // Start f1 and make its lifetime depends on current fiber
269
+ console.log('Fiber 2: spawns fiber 1');
264
270
  const childProc = fiber.spawn(f1);
265
271
  fiber.mount(childProc, proc);
266
272
  });
267
273
 
268
274
  console.log('Fiber 2 started:', fiber.resumed(main));
269
275
 
270
- // Pause the current fiber process
271
- fiber.pause(main);
272
- console.log('Fiber 2 is paused:', fiber.paused(main));
273
-
274
- // Resume the fiber
275
- fiber.resume(main);
276
- console.log('Fiber 2 is resumed:', fiber.resumed(main));
277
-
278
276
  // Wait for the fiber process to finish
279
277
  await fiber.done(main);
280
278
 
@@ -288,8 +286,12 @@ const f1 = fiber.fn(function* () {
288
286
  const main = fiber.spawn(f1);
289
287
  console.log('Fiber 1 started:', fiber.resumed(main));
290
288
 
291
- // Stop a fiber
289
+ // Interrupt a fiber
292
290
  fiber.interrupt(main);
291
+
292
+ // Execution will be stopped on the last yield
293
+ await fiber.done(main);
294
+
293
295
  console.log('Fiber 1 interrupted:', fiber.interrupted(main));
294
296
  }
295
297
 
@@ -297,11 +299,13 @@ const f1 = fiber.fn(function* () {
297
299
  console.log('------------------------');
298
300
 
299
301
  const main = fiber.spawn(f1);
300
- console.log('Fiber 1 started:', fiber.resumed(main));
302
+ logTime('Fiber 1 started');
303
+
304
+ // Wait for a time period then interrupt the fiber
305
+ fiber.timeout(main, 500);
306
+ await fiber.done(main);
301
307
 
302
- // Timeout a fiber
303
- await fiber.timeout(main, 500);
304
- console.log('Fiber 1 stopped:', fiber.interrupted(main));
308
+ logTime('Fiber 1 interrupted');
305
309
  }
306
310
  ```
307
311
 
package/channel.d.ts CHANGED
@@ -1,27 +1,20 @@
1
1
  /**
2
2
  * @module Channels
3
3
  */
4
- import type { QueueNode } from './fixed-queue.js';
4
+ import type { Node as QueueNode } from './queue.js';
5
+ import { type Lock } from './lock.js';
5
6
  /**
6
7
  * Describe a channel
7
8
  */
8
- export interface Channel<T> {
9
+ export interface Channel<T = any> extends Lock<T> {
9
10
  /**
10
11
  * The head of the value queue
11
12
  */
12
- 0: QueueNode<T>;
13
+ 2: QueueNode<T>;
13
14
  /**
14
15
  * The tail of the value queue
15
16
  */
16
- 1: QueueNode<T>;
17
- /**
18
- * The head of the Promise resolve queue
19
- */
20
- 2: QueueNode<(value?: T) => void>;
21
- /**
22
- * The tail of the Promise resolve queue
23
- */
24
- 3: QueueNode<(value?: T) => void>;
17
+ 3: QueueNode<T>;
25
18
  }
26
19
  /**
27
20
  * Create a channel
@@ -43,8 +36,4 @@ export declare const recieve: <T>(c: Channel<T>) => Promise<T | undefined>;
43
36
  * @param c
44
37
  */
45
38
  export declare const poll: <T>(c: Channel<T>) => T | undefined;
46
- /**
47
- * Resolves all pending promises of a channel
48
- * @param c
49
- */
50
- export declare const flush: <T>(c: Channel<T>) => void;
39
+ export { flush } from './lock.js';
package/channel.js CHANGED
@@ -1 +1 @@
1
- export let init=()=>{let qu=[null];let resolveQu=[null,null];return[qu,qu,resolveQu,resolveQu]};export let send=(c,t)=>{if(c[3][0]!==null)(c[3]=c[3][0])[1](t);else c[0]=c[0][0]=[null,t]};export let recieve=(c)=>c[1][0]!==null?Promise.resolve((c[1]=c[1][0])[1]):new Promise((res)=>{c[2]=c[2][0]=[null,res]});export let poll=(c)=>c[1][0]!==null?(c[0]=c[1][0])[1]:undefined;export let flush=(c)=>{while(c[3][0]!==null)(c[3]=c[3][0])[1]()};
1
+ import{acquire as lockAcquire,release as lockRelease,released as lockReleased}from"./lock.js";export let init=()=>{let resolveQu=[null];let qu=[null];return[resolveQu,resolveQu,qu,qu]};export let send=(c,t)=>{if(lockReleased(c))c[2]=c[2][0]=[null,t];else lockRelease(c,t)};export let recieve=(c)=>c[3][0]!==null?Promise.resolve((c[3]=c[3][0])[1]):lockAcquire(c);export let poll=(c)=>c[3][0]!==null?(c[3]=c[3][0])[1]:undefined;export{flush}from"./lock.js";
@@ -1,12 +1,12 @@
1
1
  /**
2
2
  * @module Dropping queues
3
3
  */
4
- import type { FixedQueue } from './fixed-queue.js';
5
- export { init } from './fixed-queue.js';
4
+ import type { Fixed } from './queue.js';
5
+ export { fixed as init } from './queue.js';
6
6
  export { pop } from './sliding-queue.js';
7
7
  /**
8
8
  * Push an item to a dropping queue
9
9
  * @param q - The queue to push to
10
10
  * @param item
11
11
  */
12
- export declare const push: <T extends {}>(q: FixedQueue<T>, item: T) => boolean;
12
+ export declare const push: <T extends {}>(q: Fixed<T>, item: T) => boolean;
package/dropping-queue.js CHANGED
@@ -1 +1 @@
1
- export{init}from"./fixed-queue.js";export{pop}from"./sliding-queue.js";export let push=(q,item)=>{if(q[0][(q[2]+1)%q[1]]!=null)return false;q[0][q[2]=(q[2]+1)%q[1]]=item;return true};
1
+ export{fixed as init}from"./queue.js";export{pop}from"./sliding-queue.js";export let push=(q,item)=>{if(q[0][(q[2]+1)%q[1]]!=null)return false;q[0][q[2]=(q[2]+1)%q[1]]=item;return true};
package/fiber.d.ts CHANGED
@@ -42,6 +42,10 @@ export declare const completed: (t: Process) => boolean;
42
42
  * Check whether the fiber has been interrupted
43
43
  */
44
44
  export declare const interrupted: (t: Process) => boolean;
45
+ /**
46
+ * Create a fiber function
47
+ * @param f
48
+ */
45
49
  export declare const fn: <const Fn extends (thread: Process, ...args: any[]) => Generator>(f: Fn) => Fn;
46
50
  /**
47
51
  * A basic fiber runtime
package/fiber.js CHANGED
@@ -1 +1 @@
1
- import{sleep}from"./index.js";export let paused=(t)=>t[1]===0;export let resumed=(t)=>t[1]===1;export let completed=(t)=>t[1]===2;export let interrupted=(t)=>t[1]===3;let invoke=async(g,thread)=>{try{let t=g.next();while(!t.done){let v=await t.value;if(thread[1]===0){let r;let p=new Promise((res)=>{r=res});thread[2]=r;await p}if(thread[1]===3)return;t=g.next(v)}thread[1]=2;return t.value}finally{if(thread[1]!==2)thread[1]=3;thread[3].forEach(stop)}};export let fn=(f)=>f;export let spawn=(f,...args)=>{let thread=[null,1,null,[]];thread[0]=invoke(f(thread,...args),thread);return thread};export let pause=(t)=>{if(t[1]===1)t[1]=0};export let resume=(t)=>{if(t[1]===0){t[1]=1;t[2]?.()}};export let interrupt=(t)=>{if(t[1]!==2){if(t[1]===0)t[2]?.();t[1]=3}};export let timeout=async(t,ms)=>{await sleep(ms);interrupt(t)};export function*join(t){return yield t[0]}export let done=(t)=>t[0];export let mount=(child,parent)=>{parent[3].push(child)};export let control=(t,signal)=>{signal.addEventListener("abort",()=>{interrupt(t)})};export function*unwrap(t){return yield t}
1
+ import{sleep}from"./index.js";export let paused=(t)=>t[1]===0;export let resumed=(t)=>t[1]===1;export let completed=(t)=>t[1]===2;export let interrupted=(t)=>t[1]===3;let invoke=async(g,thread)=>{await 0;try{let t=g.next();while(!t.done){let v=await t.value;if(thread[1]===0){let r;let p=new Promise((res)=>{r=res});thread[2]=r;await p}if(thread[1]===3)return;t=g.next(v)}thread[1]=2;return t.value}finally{if(thread[1]!==2)thread[1]=3;thread[3].forEach(interrupt)}};export let fn=(f)=>f;export let spawn=(f,...args)=>{let thread=[null,1,null,[]];thread[0]=invoke(f(thread,...args),thread);return thread};export let pause=(t)=>{if(t[1]===1)t[1]=0};export let resume=(t)=>{if(t[1]===0){t[1]=1;t[2]?.()}};export let interrupt=(t)=>{if(t[1]!==2){if(t[1]===0)t[2]?.();t[1]=3}};export let timeout=async(t,ms)=>{await sleep(ms);interrupt(t)};export function*join(t){return yield t[0]}export let done=(t)=>t[0];export let mount=(child,parent)=>{parent[3].push(child)};export let control=(t,signal)=>{signal.addEventListener("abort",()=>{interrupt(t)})};export function*unwrap(t){return yield t}
package/index.d.ts CHANGED
@@ -2,7 +2,7 @@
2
2
  * @module Other utilities
3
3
  */
4
4
  /**
5
- * Yield back to main thread.
5
+ * Continue the execution on next event loop cycle.
6
6
  *
7
7
  * You can `await` this **occasionally** in an expensive synchronous operation to avoid
8
8
  *
@@ -43,7 +43,6 @@ export declare const spawn: <const T extends any[], const R>(n: number, task: (.
43
43
  export declare const debounce: <const Args extends any[]>(f: (...args: Args) => any, ms: number) => ((...args: Args) => void);
44
44
  /**
45
45
  * Throttle function execution for a time period
46
- * @param f - The function to throttle (it must not throw errors)
47
46
  * @param ms - The time in milliseconds
48
47
  * @param limit - The call limit in the time period
49
48
  */
package/index.js CHANGED
@@ -1 +1 @@
1
- export let pause=Promise.resolve();export let sleep=globalThis.Bun?.sleep??globalThis.process?.getBuiltinModule?.("timers/promises").setTimeout??((ms)=>new Promise((res)=>{setTimeout(res,ms)}));let sharedBuf=new Int32Array(new SharedArrayBuffer(4));export let sleepSync=globalThis.Bun?.sleepSync??((ms)=>{Atomics.wait(sharedBuf,0,0,ms)});export let sequential=async(n,task,...args)=>{for(let i=0;i<n;i++)await task(...args,i)};export let spawn=(n,task,...args)=>{let arr=new Array(n);for(let i=0;i<n;i++)arr[i]=task(...args,i);return arr};export let debounce=(f,ms)=>{let id;return(...a)=>{clearTimeout(id);id=setTimeout(f,ms,...a)}};export let throttle=(ms,limit)=>{let head=[null];let tail=head;let cur=limit;let scheduled=false;let unlock=()=>{cur=limit;if(tail===head){scheduled=false;return}do{cur--;(tail=tail[0])[1]()}while(cur>0&&tail!==head);setTimeout(unlock,ms)};return()=>{if(cur===0){let r;let p=new Promise((res)=>{r=res});head=head[0]=[null,r];return p}if(!scheduled){scheduled=true;setTimeout(unlock,ms)}cur--;return pause}};
1
+ export let pause=Promise.resolve();export let sleep=globalThis.Bun?.sleep??globalThis.process?.getBuiltinModule?.("timers/promises").setTimeout??((ms)=>new Promise((res)=>{setTimeout(res,ms)}));let sharedBuf=new Int32Array(new SharedArrayBuffer(4));export let sleepSync=globalThis.Bun?.sleepSync??((ms)=>{Atomics.wait(sharedBuf,0,0,ms)});export let sequential=async(n,task,...args)=>{for(let i=0;i<n;i++)await task(...args,i)};export let spawn=(n,task,...args)=>{let arr=new Array(n);for(let i=0;i<n;i++)arr[i]=task(...args,i);return arr};export let debounce=(f,ms)=>{let id;return(...a)=>{clearTimeout(id);id=setTimeout(f,ms,...a)}};export let throttle=(ms,limit)=>{let head=[null];let tail=head;let cur=limit;let scheduled=false;let unlock=()=>{cur=limit;if(tail===head){scheduled=false;return}do{cur--;(tail=tail[0])[1]()}while(cur>0&&tail!==head);setTimeout(unlock,ms)};return()=>{if(cur===0){return new Promise((res)=>{head=head[0]=[null,res]})}if(!scheduled){scheduled=true;setTimeout(unlock,ms)}cur--;return pause}};
package/lock.d.ts ADDED
@@ -0,0 +1,36 @@
1
+ import type { Node as QueueNode } from './queue.js';
2
+ /**
3
+ * Describe a lock
4
+ */
5
+ export interface Lock<T = any> {
6
+ /**
7
+ * The head of the Promise resolve queue
8
+ */
9
+ 0: QueueNode<(value?: T) => void>;
10
+ /**
11
+ * The tail of the Promise resolve queue
12
+ */
13
+ 1: QueueNode<(value?: T) => void>;
14
+ }
15
+ /**
16
+ * Acquire an item
17
+ * @param lock
18
+ * @param value
19
+ */
20
+ export declare const acquire: <T>(lock: Lock<T>) => Promise<T | undefined>;
21
+ /**
22
+ * Release an item
23
+ * @param lock
24
+ * @param value
25
+ */
26
+ export declare const release: <T>(lock: Lock<T>, value?: T) => void;
27
+ /**
28
+ * Return true if all items are released
29
+ * @param lock
30
+ */
31
+ export declare const released: (lock: Lock) => boolean;
32
+ /**
33
+ * Release all items of a lock
34
+ * @param lock
35
+ */
36
+ export declare const flush: (lock: Lock) => void;
package/lock.js ADDED
@@ -0,0 +1 @@
1
+ export let acquire=(lock)=>new Promise((res)=>{lock[0]=lock[0][0]=[null,res]});export let release=(lock,value)=>{(lock[1]=lock[1][0])[1](value)};export let released=(lock)=>lock[1][0]===null;export let flush=(lock)=>{while(lock[1][0]!==null)(lock[1]=lock[1][0])[1]()};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ciorent",
3
- "version": "0.2.1",
3
+ "version": "0.3.0",
4
4
  "description": "A lightweight, low-overhead concurrency library",
5
5
  "homepage": "https://ciorent.netlify.app",
6
6
  "repository": {
@@ -19,13 +19,14 @@
19
19
  "types": "./index.d.ts",
20
20
  "exports": {
21
21
  "./sliding-queue": "./sliding-queue.js",
22
- "./fixed-queue": "./fixed-queue.js",
23
- "./fiber": "./fiber.js",
24
- ".": "./index.js",
22
+ "./latch": "./latch.js",
23
+ "./lock": "./lock.js",
25
24
  "./dropping-queue": "./dropping-queue.js",
25
+ "./semaphore": "./semaphore.js",
26
26
  "./channel": "./channel.js",
27
+ "./fiber": "./fiber.js",
28
+ "./queue": "./queue.js",
27
29
  "./topic": "./topic.js",
28
- "./semaphore": "./semaphore.js",
29
- "./latch": "./latch.js"
30
+ ".": "./index.js"
30
31
  }
31
32
  }
@@ -5,7 +5,7 @@
5
5
  /**
6
6
  * Describe a fixed-sized queue
7
7
  */
8
- export interface FixedQueue<T extends {}> {
8
+ export interface Fixed<T extends {}> {
9
9
  /**
10
10
  * Pre-allocated queue
11
11
  */
@@ -26,9 +26,12 @@ export interface FixedQueue<T extends {}> {
26
26
  /**
27
27
  * Describe a queue node (singly linked list node)
28
28
  */
29
- export type QueueNode<T> = [next: QueueNode<T> | null, value: T];
29
+ export interface Node<T> {
30
+ 0: Node<T> | null;
31
+ 1: T;
32
+ }
30
33
  /**
31
- * Create a fixed queue.
34
+ * Create a fixed queue
32
35
  * @param n - The queue size
33
36
  */
34
- export declare const init: <T extends {}>(n: number) => FixedQueue<T>;
37
+ export declare const fixed: <T extends {}>(n: number) => Fixed<T>;
package/queue.js ADDED
@@ -0,0 +1 @@
1
+ export let fixed=(n)=>[new Array(n),n,-1,-1];
package/semaphore.d.ts CHANGED
@@ -1,23 +1,15 @@
1
1
  /**
2
2
  * @module Semaphores
3
3
  */
4
- import type { QueueNode } from './fixed-queue.js';
4
+ import { type Lock } from './lock.js';
5
5
  /**
6
6
  * Describe a semaphore
7
7
  */
8
- export interface Semaphore {
8
+ export interface Semaphore extends Lock<undefined> {
9
9
  /**
10
10
  * Current remaining process allowed
11
11
  */
12
- 0: number;
13
- /**
14
- * The head of the Promise resolve queue
15
- */
16
- 1: QueueNode<() => void>;
17
- /**
18
- * The tail of the Promise resolve queue
19
- */
20
- 2: QueueNode<() => void>;
12
+ 2: number;
21
13
  }
22
14
  /**
23
15
  * Create a semaphore that allows n accesses
@@ -26,11 +18,11 @@ export declare const init: (n: number) => Semaphore;
26
18
  /**
27
19
  * Wait until the semaphore allows access
28
20
  */
29
- export declare const pause: (s: Semaphore) => Promise<void>;
21
+ export declare const acquire: (s: Semaphore) => Promise<void>;
30
22
  /**
31
23
  * Signal to the semaphore to release access
32
24
  */
33
- export declare const signal: (s: Semaphore) => void;
25
+ export declare const release: (s: Semaphore) => void;
34
26
  /**
35
27
  * Bind a task to a semaphore
36
28
  */
package/semaphore.js CHANGED
@@ -1 +1 @@
1
- import{pause as resolvedPromise}from"./index.js";export let init=(n)=>{let root=[null];return[n,root,root]};export let pause=(s)=>{s[0]--;if(s[0]<0){let r;let p=new Promise((res)=>{r=res});s[1]=s[1][0]=[null,r];return p}return resolvedPromise};export let signal=(s)=>{if(s[0]<0)(s[2]=s[2][0])[1]();s[0]++};export let bind=(f,s)=>async(...a)=>{s[0]--;if(s[0]<0){let r;let p=new Promise((res)=>{r=res});s[1]=s[1][0]=[null,r];await p}try{return await f(...a)}finally{if(s[0]<0)(s[2]=s[2][0])[1]();s[0]++}};
1
+ import{pause as resolvedPromise}from"./index.js";import{acquire as lockAcquire,release as lockRelease}from"./lock.js";export let init=(n)=>{let root=[null];return[root,root,n]};export let acquire=(s)=>{s[2]--;return s[2]>=0?resolvedPromise:lockAcquire(s)};export let release=(s)=>{if(s[2]<0)lockRelease(s);s[2]++};export let bind=(f,s)=>async(...a)=>{s[2]--;if(s[2]<0)await acquire(s);try{return await f(...a)}finally{if(s[2]<0)release(s);s[2]++}};
@@ -1,16 +1,16 @@
1
1
  /**
2
2
  * @module Sliding queues
3
3
  */
4
- import type { FixedQueue } from './fixed-queue.js';
5
- export { init } from './fixed-queue.js';
4
+ import type { Fixed } from './queue.js';
5
+ export { fixed as init } from './queue.js';
6
6
  /**
7
7
  * Push an item to a sliding queue
8
8
  * @param q - The queue to push to
9
9
  * @param item
10
10
  */
11
- export declare const push: <T extends {}>(q: FixedQueue<T>, item: T) => void;
11
+ export declare const push: <T extends {}>(q: Fixed<T>, item: T) => void;
12
12
  /**
13
13
  * Pop an item from the queue
14
14
  * @param q - The queue to pop from
15
15
  */
16
- export declare const pop: <T extends {}>(q: FixedQueue<T>) => T | undefined;
16
+ export declare const pop: <T extends {}>(q: Fixed<T>) => T | undefined;
package/sliding-queue.js CHANGED
@@ -1 +1 @@
1
- export{init}from"./fixed-queue.js";export let push=(q,item)=>{q[0][q[2]=(q[2]+1)%q[1]]=item};export let pop=(q)=>{let val=q[0][(q[3]+1)%q[1]];if(val!=null){q[0][q[3]=(q[3]+1)%q[1]]=null;return val}};
1
+ export{fixed as init}from"./queue.js";export let push=(q,item)=>{q[0][q[2]=(q[2]+1)%q[1]]=item};export let pop=(q)=>{let val=q[0][(q[3]+1)%q[1]];if(val!=null){q[0][q[3]=(q[3]+1)%q[1]]=null;return val}};
package/topic.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * @module Pubsub
3
3
  */
4
- import type { QueueNode } from './fixed-queue.js';
4
+ import type { Node as QueueNode } from './queue.js';
5
5
  /**
6
6
  * Describe a topic
7
7
  */
@@ -13,11 +13,7 @@ export interface Topic<T extends {}> {
13
13
  /**
14
14
  * The waiting subscriber resolves
15
15
  */
16
- 1: ((res?: T) => void)[];
17
- /**
18
- * The waiting subscribers
19
- */
20
- 2: Subscriber<T>[];
16
+ 1: ((res: QueueNode<T>) => void)[];
21
17
  }
22
18
  /**
23
19
  * Create a topic
package/topic.js CHANGED
@@ -1 +1 @@
1
- export let init=()=>[[null],[],[]];export let subscribe=(t)=>[t,t[0]];export let publish=(t,value)=>{let head=t[0]=t[0][0]=[null,value];for(let i=0,res=t[1],subs=t[2];i<res.length;i++){res[i](value);subs[i][1]=head}t[1]=[];t[2]=[]};export let flush=(t)=>{let head=t[0]=[null];for(let i=0,res=t[1],subs=t[2];i<res.length;i++){res[i]();subs[i][1]=head}t[1]=[];t[2]=[]};export let poll=(t)=>t[1][0]!==null?(t[1]=t[1][0])[1]:undefined;export let recieve=(t)=>{if(t[1][0]!==null)return Promise.resolve((t[1]=t[1][0])[1]);let topic=t[0];topic[2].push(t);return new Promise((res)=>{topic[1].push(res)})};
1
+ export let init=()=>[[null],[],[]];export let subscribe=(t)=>[t,t[0]];export let publish=(t,value)=>{let head=t[0]=t[0][0]=[null,value];for(let i=0,res=t[1];i<res.length;i++)res[i](head);t[1]=[]};export let flush=(t)=>{let head=t[0]=t[0][0]=[null,undefined];for(let i=0,res=t[1];i<res.length;i++)res[i](head);t[1]=[]};export let poll=(t)=>t[1][0]!==null?(t[1]=t[1][0])[1]:undefined;export let recieve=async(t)=>t[1][0]!==null?(t[1]=t[1][0])[1]:(t[1]=await new Promise((res)=>{t[0][1].push(res)}))[1];
package/fixed-queue.js DELETED
@@ -1 +0,0 @@
1
- export let init=(n)=>[new Array(n),n,-1,-1];