ciorent 0.2.1 → 0.3.1
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 +93 -89
- package/channel.d.ts +6 -17
- package/channel.js +1 -1
- package/dropping-queue.d.ts +3 -3
- package/dropping-queue.js +1 -1
- package/fiber.d.ts +4 -0
- package/fiber.js +1 -1
- package/index.d.ts +2 -3
- package/index.js +1 -1
- package/latch.js +1 -1
- package/lock.d.ts +38 -0
- package/lock.js +1 -0
- package/package.json +7 -6
- package/{fixed-queue.d.ts → queue.d.ts} +7 -5
- package/queue.js +1 -0
- package/semaphore.d.ts +5 -13
- package/semaphore.js +1 -1
- package/sliding-queue.d.ts +4 -4
- package/sliding-queue.js +1 -1
- package/topic.d.ts +2 -6
- package/topic.js +1 -1
- package/fixed-queue.js +0 -1
package/README.md
CHANGED
@@ -74,8 +74,8 @@ co.spawn(8, async (id) => {
|
|
74
74
|
});
|
75
75
|
```
|
76
76
|
|
77
|
-
####
|
78
|
-
|
77
|
+
#### Yield
|
78
|
+
Continue the execution on next tick, allowing other asynchronous tasks to run.
|
79
79
|
```ts
|
80
80
|
import * as co from 'ciorent';
|
81
81
|
|
@@ -85,7 +85,7 @@ const task1 = async () => {
|
|
85
85
|
|
86
86
|
// Yield control back to the runtime, allowing it to
|
87
87
|
// schedule other tasks
|
88
|
-
await co.
|
88
|
+
await co.nextTick;
|
89
89
|
|
90
90
|
// Simulate heavy operation
|
91
91
|
for (let i = 0; i < (Math.random() + 15) * 1e6; i++)
|
@@ -106,42 +106,69 @@ task1();
|
|
106
106
|
task2();
|
107
107
|
```
|
108
108
|
|
109
|
-
###
|
110
|
-
|
109
|
+
### Pubsub
|
110
|
+
A fast, simple publish-subscribe API.
|
111
111
|
|
112
112
|
```ts
|
113
|
-
import * as
|
113
|
+
import * as topic from 'ciorent/topic';
|
114
114
|
import * as co from 'ciorent';
|
115
115
|
|
116
|
-
const
|
116
|
+
const messages = topic.init<number>();
|
117
117
|
|
118
|
-
|
119
|
-
|
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
|
-
|
122
|
-
console.log('Sent', i);
|
122
|
+
topic.publish(messages, i);
|
123
123
|
}
|
124
124
|
|
125
|
-
// Resolve all waiting promises
|
126
|
-
//
|
127
|
-
|
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
|
-
//
|
133
|
-
const x = await
|
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
|
-
|
137
|
-
|
138
|
-
}
|
142
|
+
publisher();
|
143
|
+
```
|
139
144
|
|
140
|
-
|
141
|
-
|
145
|
+
### Semaphore
|
146
|
+
Semaphore is a concurrency primitive used to control access to a common resource by multiple processes.
|
142
147
|
|
143
|
-
|
144
|
-
|
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.nextTick;
|
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
|
-
###
|
175
|
-
|
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
|
205
|
+
import * as channel from 'ciorent/channel';
|
208
206
|
import * as co from 'ciorent';
|
209
207
|
|
210
|
-
const
|
208
|
+
const c = channel.init<number>();
|
211
209
|
|
212
|
-
|
213
|
-
|
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
|
-
|
213
|
+
channel.send(c, i);
|
214
|
+
console.log('Sent', i);
|
217
215
|
}
|
218
216
|
|
219
|
-
// Resolve all waiting promises
|
220
|
-
//
|
221
|
-
|
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
|
-
//
|
230
|
-
const x = await
|
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
|
-
|
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
|
-
//
|
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
|
-
|
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
|
-
|
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 './
|
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
|
-
|
13
|
+
2: QueueNode<T>;
|
13
14
|
/**
|
14
15
|
* The tail of the value queue
|
15
16
|
*/
|
16
|
-
|
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
|
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";
|
package/dropping-queue.d.ts
CHANGED
@@ -1,12 +1,12 @@
|
|
1
1
|
/**
|
2
2
|
* @module Dropping queues
|
3
3
|
*/
|
4
|
-
import type {
|
5
|
-
export { init } from './
|
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:
|
12
|
+
export declare const push: <T extends {}>(q: Fixed<T>, item: T) => boolean;
|
package/dropping-queue.js
CHANGED
@@ -1 +1 @@
|
|
1
|
-
export{init}from"./
|
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(
|
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,13 +2,13 @@
|
|
2
2
|
* @module Other utilities
|
3
3
|
*/
|
4
4
|
/**
|
5
|
-
*
|
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
|
*
|
9
9
|
* blocking the main thread and let other asynchronous task to run.
|
10
10
|
*/
|
11
|
-
export declare const
|
11
|
+
export declare const nextTick: Promise<void>;
|
12
12
|
/**
|
13
13
|
* Sleep for a duration.
|
14
14
|
* @param ms - Sleep duration in milliseconds
|
@@ -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
|
1
|
+
export let nextTick=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 nextTick}};
|
package/latch.js
CHANGED
@@ -1 +1 @@
|
|
1
|
-
import{
|
1
|
+
import{nextTick as endPromise}from"./index.js";export let init=()=>{let r;return[new Promise((res)=>{r=res}),r]};export let pause=(latch)=>latch[0];export let open=(latch)=>{latch[1]();latch[0]=endPromise};export let close=(latch)=>{if(latch[0]===endPromise){let r;latch[0]=new Promise((res)=>{r=res});latch[1]=r}};
|
package/lock.d.ts
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
/**
|
2
|
+
* @module Lock utilities
|
3
|
+
*/
|
4
|
+
import type { Node as QueueNode } from './queue.js';
|
5
|
+
/**
|
6
|
+
* Describe a lock
|
7
|
+
*/
|
8
|
+
export interface Lock<T = any> {
|
9
|
+
/**
|
10
|
+
* The head of the Promise resolve queue
|
11
|
+
*/
|
12
|
+
0: QueueNode<(value?: T) => void>;
|
13
|
+
/**
|
14
|
+
* The tail of the Promise resolve queue
|
15
|
+
*/
|
16
|
+
1: QueueNode<(value?: T) => void>;
|
17
|
+
}
|
18
|
+
/**
|
19
|
+
* Acquire an item
|
20
|
+
* @param lock
|
21
|
+
*/
|
22
|
+
export declare const acquire: <T>(lock: Lock<T>) => Promise<T | undefined>;
|
23
|
+
/**
|
24
|
+
* Release an item
|
25
|
+
* @param lock
|
26
|
+
* @param value
|
27
|
+
*/
|
28
|
+
export declare const release: <T>(lock: Lock<T>, value?: T) => void;
|
29
|
+
/**
|
30
|
+
* Return true if all items are released
|
31
|
+
* @param lock
|
32
|
+
*/
|
33
|
+
export declare const released: (lock: Lock) => boolean;
|
34
|
+
/**
|
35
|
+
* Release all items of a lock
|
36
|
+
* @param lock
|
37
|
+
*/
|
38
|
+
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.
|
3
|
+
"version": "0.3.1",
|
4
4
|
"description": "A lightweight, low-overhead concurrency library",
|
5
5
|
"homepage": "https://ciorent.netlify.app",
|
6
6
|
"repository": {
|
@@ -18,14 +18,15 @@
|
|
18
18
|
"main": "./index.js",
|
19
19
|
"types": "./index.d.ts",
|
20
20
|
"exports": {
|
21
|
-
"./
|
22
|
-
"./fixed-queue": "./fixed-queue.js",
|
23
|
-
"./fiber": "./fiber.js",
|
24
|
-
".": "./index.js",
|
21
|
+
"./latch": "./latch.js",
|
25
22
|
"./dropping-queue": "./dropping-queue.js",
|
23
|
+
"./sliding-queue": "./sliding-queue.js",
|
26
24
|
"./channel": "./channel.js",
|
25
|
+
"./fiber": "./fiber.js",
|
26
|
+
"./lock": "./lock.js",
|
27
|
+
"./queue": "./queue.js",
|
27
28
|
"./topic": "./topic.js",
|
28
29
|
"./semaphore": "./semaphore.js",
|
29
|
-
"
|
30
|
+
".": "./index.js"
|
30
31
|
}
|
31
32
|
}
|
@@ -1,11 +1,10 @@
|
|
1
1
|
/**
|
2
|
-
* @private
|
3
2
|
* @module Queue utilities
|
4
3
|
*/
|
5
4
|
/**
|
6
5
|
* Describe a fixed-sized queue
|
7
6
|
*/
|
8
|
-
export interface
|
7
|
+
export interface Fixed<T extends {}> {
|
9
8
|
/**
|
10
9
|
* Pre-allocated queue
|
11
10
|
*/
|
@@ -26,9 +25,12 @@ export interface FixedQueue<T extends {}> {
|
|
26
25
|
/**
|
27
26
|
* Describe a queue node (singly linked list node)
|
28
27
|
*/
|
29
|
-
export
|
28
|
+
export interface Node<T> {
|
29
|
+
0: Node<T> | null;
|
30
|
+
1: T;
|
31
|
+
}
|
30
32
|
/**
|
31
|
-
* Create a fixed queue
|
33
|
+
* Create a fixed queue
|
32
34
|
* @param n - The queue size
|
33
35
|
*/
|
34
|
-
export declare const
|
36
|
+
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
|
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
|
-
|
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
|
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
|
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{
|
1
|
+
import{nextTick 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]++}};
|
package/sliding-queue.d.ts
CHANGED
@@ -1,16 +1,16 @@
|
|
1
1
|
/**
|
2
2
|
* @module Sliding queues
|
3
3
|
*/
|
4
|
-
import type {
|
5
|
-
export { init } from './
|
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:
|
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:
|
16
|
+
export declare const pop: <T extends {}>(q: Fixed<T>) => T | undefined;
|
package/sliding-queue.js
CHANGED
@@ -1 +1 @@
|
|
1
|
-
export{init}from"./
|
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 './
|
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
|
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]
|
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];
|