ciorent 0.4.0 → 0.4.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.
- package/README.md +0 -264
- package/fiber.d.ts +48 -67
- package/fiber.js +1 -1
- package/index.d.ts +33 -39
- package/index.js +1 -1
- package/package.json +20 -26
- package/queue.d.ts +11 -16
- package/queue.js +1 -0
- package/semaphore.d.ts +14 -18
- package/semaphore.js +1 -1
- package/stream.d.ts +17 -21
- package/stream.js +1 -1
- package/topic.d.ts +0 -45
- package/topic.js +0 -1
package/README.md
CHANGED
@@ -7,267 +7,3 @@ A lightweight, low-overhead concurrency library.
|
|
7
7
|
- Fully type-safe.
|
8
8
|
|
9
9
|
## Examples
|
10
|
-
### Utilities
|
11
|
-
#### Spawning tasks
|
12
|
-
Utilities to create and run tasks.
|
13
|
-
```ts
|
14
|
-
import * as co from 'ciorent';
|
15
|
-
|
16
|
-
const task = async (id: number) => {
|
17
|
-
await co.sleep((10 - id) * 20 + 50);
|
18
|
-
console.log('Task', id, 'done');
|
19
|
-
}
|
20
|
-
|
21
|
-
// Spawn and run 5 tasks sequentially
|
22
|
-
console.log('Running 5 tasks sequentially:');
|
23
|
-
await co.sequential(5, task);
|
24
|
-
|
25
|
-
// Spawn and run 5 tasks concurrently
|
26
|
-
console.log('Running 5 tasks concurrently:');
|
27
|
-
await Promise.all(co.spawn(5, task));
|
28
|
-
```
|
29
|
-
|
30
|
-
#### Sleep
|
31
|
-
Cross-runtime synchronous and asynchronous sleep functions.
|
32
|
-
```ts
|
33
|
-
import * as co from 'ciorent';
|
34
|
-
|
35
|
-
const logTime = (label: string) => console.log(`${label}: ${Math.floor(performance.now())}ms`);
|
36
|
-
|
37
|
-
logTime('Start');
|
38
|
-
|
39
|
-
// Non-blocking
|
40
|
-
await co.sleep(500);
|
41
|
-
logTime('After about 0.5s');
|
42
|
-
|
43
|
-
// This blocks the event loop
|
44
|
-
// On the browser this only works in workers and blocks the worker thread
|
45
|
-
co.sleepSync(500);
|
46
|
-
logTime('After another 0.5s');
|
47
|
-
```
|
48
|
-
|
49
|
-
#### Debounce
|
50
|
-
Postpones execution until after an idle period.
|
51
|
-
```ts
|
52
|
-
import * as co from 'ciorent';
|
53
|
-
|
54
|
-
const fn = co.debounce((id: number) => {
|
55
|
-
console.log('ID:', id);
|
56
|
-
}, 500);
|
57
|
-
|
58
|
-
fn(1); // fn(1) gets skipped
|
59
|
-
await co.sleep(100);
|
60
|
-
fn(2); // fn(2) gets executed
|
61
|
-
```
|
62
|
-
|
63
|
-
#### Throttle
|
64
|
-
Executes a function at a regular interval.
|
65
|
-
```ts
|
66
|
-
import * as co from 'ciorent';
|
67
|
-
|
68
|
-
// Allow 2 calls in 500ms
|
69
|
-
const throttle = co.throttle(500, 2);
|
70
|
-
|
71
|
-
co.spawn(8, async (id) => {
|
72
|
-
await throttle();
|
73
|
-
console.log(`${id}: ${Math.floor(performance.now())}ms`);
|
74
|
-
});
|
75
|
-
```
|
76
|
-
|
77
|
-
#### Yield
|
78
|
-
Continue the execution on next tick, allowing other asynchronous tasks to run.
|
79
|
-
```ts
|
80
|
-
import * as co from 'ciorent';
|
81
|
-
|
82
|
-
const logTime = (label: string) => console.log(`${label}: ${Math.floor(performance.now())}ms`);
|
83
|
-
|
84
|
-
// Expensive sync task
|
85
|
-
const task1 = async () => {
|
86
|
-
let x = 0;
|
87
|
-
|
88
|
-
// Simulate heavy operation
|
89
|
-
for (let i = 0, l = (Math.random() + 15) * 1e6; i < l; i++) {
|
90
|
-
// Yield control back occasionally to the runtime, allowing
|
91
|
-
// it to schedule other tasks
|
92
|
-
if (i % 1e5 === 0)
|
93
|
-
await co.nextTick;
|
94
|
-
|
95
|
-
x += Math.random() * 32 + i * Math.round(Math.random() * 16);
|
96
|
-
}
|
97
|
-
|
98
|
-
console.log('Task 1 result:', x);
|
99
|
-
};
|
100
|
-
|
101
|
-
// Short async task
|
102
|
-
const task2 = async (id: number) => {
|
103
|
-
logTime('Task 2.' + id + ' start fetching');
|
104
|
-
await fetch('http://localhost:3000').catch(() => {});
|
105
|
-
logTime('Task 2.' + id + ' done fetching');
|
106
|
-
};
|
107
|
-
|
108
|
-
task1();
|
109
|
-
|
110
|
-
// Task 2 will not get blocked by task 1
|
111
|
-
co.spawn(5, task2);
|
112
|
-
```
|
113
|
-
|
114
|
-
### Pubsub
|
115
|
-
Pubsub allows broadcasting messages to topics that can be recieved by subscribers.
|
116
|
-
|
117
|
-
```ts
|
118
|
-
import * as topic from 'ciorent/topic';
|
119
|
-
import * as co from 'ciorent';
|
120
|
-
|
121
|
-
const numbers = topic.init<number>();
|
122
|
-
|
123
|
-
// Spawn 3 tasks that subscribe to the topic
|
124
|
-
co.spawn(3, async (id) => {
|
125
|
-
const subscriber = topic.subscribe(numbers);
|
126
|
-
|
127
|
-
while (true) {
|
128
|
-
const msg = await topic.dispatch(subscriber);
|
129
|
-
if (msg == null) return;
|
130
|
-
console.log('Task', id, 'recieved:', msg);
|
131
|
-
}
|
132
|
-
});
|
133
|
-
|
134
|
-
// Publish messages to the topic
|
135
|
-
for (let i = 0; i < 3; i++) {
|
136
|
-
topic.publish(numbers, i);
|
137
|
-
await co.nextTick;
|
138
|
-
}
|
139
|
-
|
140
|
-
// Send undefined to every topic
|
141
|
-
topic.flush(numbers);
|
142
|
-
```
|
143
|
-
|
144
|
-
### Stream
|
145
|
-
Send and recieve data asynchronously through streams.
|
146
|
-
|
147
|
-
```ts
|
148
|
-
import * as stream from 'ciorent/stream';
|
149
|
-
import * as co from 'ciorent';
|
150
|
-
|
151
|
-
const numbers = stream.init<number>();
|
152
|
-
|
153
|
-
// Spawn 3 tasks that read from the stream
|
154
|
-
co.spawn(3, async (id) => {
|
155
|
-
while (true) {
|
156
|
-
const msg = await stream.read(numbers);
|
157
|
-
if (msg == null) return;
|
158
|
-
console.log('Task', id, 'recieved:', msg);
|
159
|
-
}
|
160
|
-
});
|
161
|
-
|
162
|
-
// Write messages to the stream
|
163
|
-
for (let i = 0; i < 3; i++) {
|
164
|
-
stream.write(numbers, i);
|
165
|
-
await co.nextTick;
|
166
|
-
}
|
167
|
-
|
168
|
-
// Send undefined to every stream
|
169
|
-
stream.flush(numbers);
|
170
|
-
```
|
171
|
-
|
172
|
-
### Semaphore
|
173
|
-
Semaphore is a concurrency primitive used to control access to a common resource by multiple processes.
|
174
|
-
|
175
|
-
```ts
|
176
|
-
import * as semaphore from 'ciorent/semaphore';
|
177
|
-
import * as co from 'ciorent';
|
178
|
-
|
179
|
-
// Only allow 2 task to run concurrently
|
180
|
-
const sem = semaphore.init(2);
|
181
|
-
|
182
|
-
const task = async (id: number) => {
|
183
|
-
// Acquire the semaphore or wait for the semaphore to be available
|
184
|
-
await semaphore.acquire(sem);
|
185
|
-
|
186
|
-
console.log('Task', id, 'started');
|
187
|
-
|
188
|
-
// Let the main thread schedules other tasks
|
189
|
-
for (let i = 1; i <= 5; i++) await co.nextTick;
|
190
|
-
|
191
|
-
console.log('Task', id, 'end');
|
192
|
-
|
193
|
-
// Release the semaphore
|
194
|
-
semaphore.release(sem);
|
195
|
-
}
|
196
|
-
|
197
|
-
// Try to run 5 tasks concurrently
|
198
|
-
co.spawn(5, task);
|
199
|
-
```
|
200
|
-
|
201
|
-
### Fibers
|
202
|
-
Virtual threads with more controlled execution.
|
203
|
-
|
204
|
-
```ts
|
205
|
-
import * as co from 'ciorent';
|
206
|
-
import * as fiber from 'ciorent/fiber';
|
207
|
-
|
208
|
-
const logTime = (label: string) => console.log(`${label}: ${Math.floor(performance.now())}ms`);
|
209
|
-
|
210
|
-
const f1 = fiber.fn(function* () {
|
211
|
-
// Wait for a promise
|
212
|
-
console.log('Fiber 1 waiting: 1s');
|
213
|
-
yield co.sleep(1000);
|
214
|
-
|
215
|
-
// Wait for a promise and return its result
|
216
|
-
const res = yield* fiber.unwrap(Promise.resolve(1));
|
217
|
-
console.log('Fiber 1 recieved:', res);
|
218
|
-
|
219
|
-
return Math.random();
|
220
|
-
});
|
221
|
-
|
222
|
-
{
|
223
|
-
// Start the fiber process on next event loop cycle
|
224
|
-
const main = fiber.spawn(function* (proc) {
|
225
|
-
// Start f1, wait for the process to complete and get the result
|
226
|
-
console.log('Fiber 2: joins fiber 1');
|
227
|
-
const res = yield* fiber.join(fiber.spawn(f1));
|
228
|
-
console.log('Fiber 2 recieved:', res);
|
229
|
-
|
230
|
-
// Start f1 and make its lifetime depends on current fiber
|
231
|
-
console.log('Fiber 2: spawns fiber 1');
|
232
|
-
const childProc = fiber.spawn(f1);
|
233
|
-
fiber.mount(childProc, proc);
|
234
|
-
});
|
235
|
-
|
236
|
-
console.log('Fiber 2 started:', fiber.resumed(main));
|
237
|
-
|
238
|
-
// Wait for the fiber process to finish
|
239
|
-
await fiber.done(main);
|
240
|
-
|
241
|
-
// Check finish status
|
242
|
-
console.log('Fiber 2 completed:', fiber.completed(main));
|
243
|
-
}
|
244
|
-
|
245
|
-
{
|
246
|
-
console.log('------------------------');
|
247
|
-
|
248
|
-
const main = fiber.spawn(f1);
|
249
|
-
console.log('Fiber 1 started:', fiber.resumed(main));
|
250
|
-
|
251
|
-
// Interrupt a fiber
|
252
|
-
fiber.interrupt(main);
|
253
|
-
|
254
|
-
// Execution will be stopped on the last yield
|
255
|
-
await fiber.done(main);
|
256
|
-
|
257
|
-
console.log('Fiber 1 interrupted:', fiber.interrupted(main));
|
258
|
-
}
|
259
|
-
|
260
|
-
{
|
261
|
-
console.log('------------------------');
|
262
|
-
|
263
|
-
const main = fiber.spawn(f1);
|
264
|
-
logTime('Fiber 1 started');
|
265
|
-
|
266
|
-
// Wait for a time period then interrupt the fiber
|
267
|
-
fiber.timeout(main, 500);
|
268
|
-
await fiber.done(main);
|
269
|
-
|
270
|
-
logTime('Fiber 1 interrupted');
|
271
|
-
}
|
272
|
-
```
|
273
|
-
|
package/fiber.d.ts
CHANGED
@@ -1,89 +1,70 @@
|
|
1
1
|
/**
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
*/
|
20
|
-
export declare const paused: (t: Process) => boolean;
|
21
|
-
/**
|
22
|
-
* Check whether the fiber is running
|
23
|
-
*/
|
24
|
-
export declare const resumed: (t: Process) => boolean;
|
25
|
-
/**
|
26
|
-
* Check whether the fiber has completed
|
27
|
-
*/
|
2
|
+
* Describe a fiber process
|
3
|
+
*/
|
4
|
+
export type Process<TReturn = unknown> = [proc: Promise<TReturn | undefined>, status: 1 | 2 | 3, children: Process[]];
|
5
|
+
/**
|
6
|
+
* Describe a fiber runtime
|
7
|
+
*/
|
8
|
+
export type Runtime = <
|
9
|
+
const TReturn,
|
10
|
+
const Args extends any[]
|
11
|
+
>(gen: (proc: Process<TReturn>, ...args: Args) => Generator<any, TReturn>, ...args: Args) => Process<TReturn>;
|
12
|
+
/**
|
13
|
+
* Check whether the fiber is running
|
14
|
+
*/
|
15
|
+
export declare const running: (t: Process) => boolean;
|
16
|
+
/**
|
17
|
+
* Check whether the fiber has completed
|
18
|
+
*/
|
28
19
|
export declare const completed: (t: Process) => boolean;
|
29
20
|
/**
|
30
|
-
|
31
|
-
|
21
|
+
* Check whether the fiber has been interrupted
|
22
|
+
*/
|
32
23
|
export declare const interrupted: (t: Process) => boolean;
|
33
24
|
/**
|
34
|
-
|
35
|
-
|
36
|
-
|
25
|
+
* Create a fiber function
|
26
|
+
* @param f
|
27
|
+
*/
|
37
28
|
export declare const fn: <const Fn extends (thread: Process, ...args: any[]) => Generator>(f: Fn) => Fn;
|
38
29
|
/**
|
39
|
-
|
40
|
-
|
41
|
-
|
30
|
+
* A basic fiber runtime
|
31
|
+
* @param g
|
32
|
+
*/
|
42
33
|
export declare const spawn: Runtime;
|
43
34
|
/**
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
export declare const pause: (t: Process) => void;
|
48
|
-
/**
|
49
|
-
* Resume the execution of a fiber
|
50
|
-
* @param t
|
51
|
-
*/
|
52
|
-
export declare const resume: (t: Process) => void;
|
53
|
-
/**
|
54
|
-
* Interrupt the execution of a fiber
|
55
|
-
* @param t
|
56
|
-
*/
|
35
|
+
* Interrupt the execution of a fiber
|
36
|
+
* @param t
|
37
|
+
*/
|
57
38
|
export declare const interrupt: (t: Process) => void;
|
58
39
|
/**
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
40
|
+
* Timeout a fiber
|
41
|
+
* @param t
|
42
|
+
* @param ms
|
43
|
+
*/
|
63
44
|
export declare const timeout: (t: Process, ms: number) => Promise<void>;
|
64
45
|
/**
|
65
|
-
|
66
|
-
|
67
|
-
|
46
|
+
* Wait for a fiber and retrieve its result
|
47
|
+
* @param t
|
48
|
+
*/
|
68
49
|
export declare function join<T extends Process>(t: T): Generator<Awaited<T[0]>, Awaited<T[0]>>;
|
69
50
|
/**
|
70
|
-
|
71
|
-
|
72
|
-
|
51
|
+
* Wait for a fiber to finish and retrieve its result
|
52
|
+
* @param t
|
53
|
+
*/
|
73
54
|
export declare const done: <T extends Process>(t: T) => T[0];
|
74
55
|
/**
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
56
|
+
* Mount child fiber lifetime to parent lifetime
|
57
|
+
* @param child
|
58
|
+
* @param parent
|
59
|
+
*/
|
79
60
|
export declare const mount: (child: Process, parent: Process) => void;
|
80
61
|
/**
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
62
|
+
* Control the fiber with an abort signal
|
63
|
+
* @param t
|
64
|
+
* @param signal
|
65
|
+
*/
|
85
66
|
export declare const control: (t: Process, signal: AbortSignal) => void;
|
86
67
|
/**
|
87
|
-
|
88
|
-
|
68
|
+
* Unwrap a promise result
|
69
|
+
*/
|
89
70
|
export declare function unwrap<T extends Promise<any>>(t: T): Generator<Awaited<T>, Awaited<T>>;
|
package/fiber.js
CHANGED
@@ -1 +1 @@
|
|
1
|
-
import{sleep}from"./index.js";export let
|
1
|
+
import{nextTick,sleep}from"./index.js";export let running=e=>e[1]===1;export let completed=e=>e[1]===2;export let interrupted=e=>e[1]===3;let invoke=async(f,p)=>{await nextTick;try{let e=f.next();for(;!e.done;){let m=await e.value;if(p[1]===3)return;e=f.next(m)}return p[1]=2,e.value}finally{p[1]!==2&&(p[1]=3),p[2].forEach(interrupt)}};export let fn=e=>e;export let spawn=(e,...f)=>{let p=[null,1,[]];return p[0]=invoke(e(p,...f),p),p};export let interrupt=e=>{e[1]!==2&&(e[1]=3)};export let timeout=async(e,p)=>{await sleep(p),interrupt(e)};export function*join(e){return yield e[0]}export let done=e=>e[0];export let mount=(e,f)=>{f[2].push(e)};export let control=(e,f)=>{f.addEventListener(`abort`,()=>{interrupt(e)})};export function*unwrap(e){return yield e}
|
package/index.d.ts
CHANGED
@@ -1,49 +1,43 @@
|
|
1
1
|
/**
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
*
|
9
|
-
* blocking the main thread and let other asynchronous task to run.
|
10
|
-
*/
|
2
|
+
* Continue the execution on next event loop cycle.
|
3
|
+
*
|
4
|
+
* You can `await` this **occasionally** in an expensive synchronous operation to avoid
|
5
|
+
*
|
6
|
+
* blocking the main thread and let other asynchronous task to run.
|
7
|
+
*/
|
11
8
|
export declare const nextTick: Promise<void>;
|
12
9
|
/**
|
13
|
-
|
14
|
-
|
15
|
-
|
10
|
+
* Sleep for a duration.
|
11
|
+
* @param ms - Sleep duration in milliseconds
|
12
|
+
*/
|
16
13
|
export declare const sleep: (ms: number) => Promise<void>;
|
17
14
|
/**
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
15
|
+
* Sleep for a duration synchronously.
|
16
|
+
*
|
17
|
+
* This method blocks the current thread.
|
18
|
+
*
|
19
|
+
* On the browser it only works in workers.
|
20
|
+
* @param ms - Sleep duration in milliseconds
|
21
|
+
*/
|
25
22
|
export declare const sleepSync: (ms: number) => void;
|
26
23
|
/**
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
24
|
+
* Spawn n sequential task
|
25
|
+
* @param n
|
26
|
+
* @param task - The function to run
|
27
|
+
*/
|
31
28
|
export declare const sequential: <const T extends any[]>(n: number, task: (...args: [...T, id: number]) => Promise<any>, ...args: T) => Promise<void>;
|
32
29
|
/**
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
export declare const spawn: <
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
* @param ms - The time in milliseconds
|
47
|
-
* @param limit - The call limit in the time period
|
48
|
-
*/
|
30
|
+
* Spawn n concurrent tasks
|
31
|
+
* @param n
|
32
|
+
* @param task - The function to run
|
33
|
+
*/
|
34
|
+
export declare const spawn: <
|
35
|
+
const T extends any[],
|
36
|
+
const R
|
37
|
+
>(n: number, task: (...args: [...T, id: number]) => Promise<R>, ...args: T) => Promise<R>[];
|
38
|
+
/**
|
39
|
+
* Throttle function execution for a time period
|
40
|
+
* @param ms - The time in milliseconds
|
41
|
+
* @param limit - The call limit in the time period
|
42
|
+
*/
|
49
43
|
export declare const throttle: (ms: number, limit: number) => (() => Promise<void>);
|
package/index.js
CHANGED
@@ -1 +1 @@
|
|
1
|
-
export let nextTick=Promise.resolve();export let sleep=globalThis.Bun?.sleep??globalThis.process?.getBuiltinModule?.(
|
1
|
+
export let nextTick=Promise.resolve();export let sleep=globalThis.Bun?.sleep??globalThis.process?.getBuiltinModule?.(`timers/promises`).setTimeout??(e=>new Promise(t=>{setTimeout(t,e)}));let sharedBuf=new Int32Array(new SharedArrayBuffer(4));export let sleepSync=globalThis.Bun?.sleepSync??(e=>{Atomics.wait(sharedBuf,0,0,e)});export let sequential=async(e,t,...n)=>{for(let r=0;r<e;r++)await t(...n,r)};export let spawn=(e,t,...n)=>{let r=Array(e);for(let i=0;i<e;i++)r[i]=t(...n,i);return r};export let throttle=(e,t)=>{let n=[null],r=n,i=e=>{n=n[0]=[null,e]},a=t,o=!1,s=()=>{if(a=t,r===n){o=!1;return}do a--,(r=r[0])[1]();while(a>0&&r!==n);setTimeout(s,e)};return async()=>{if(a===0)return new Promise(i);o||(o=!0,setTimeout(s,e)),a--}};
|
package/package.json
CHANGED
@@ -1,28 +1,22 @@
|
|
1
1
|
{
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
"./queue": "./queue.d.ts",
|
23
|
-
"./semaphore": "./semaphore.js",
|
24
|
-
"./stream": "./stream.js",
|
25
|
-
"./topic": "./topic.js",
|
26
|
-
".": "./index.js"
|
27
|
-
}
|
2
|
+
"name": "ciorent",
|
3
|
+
"version": "0.4.2",
|
4
|
+
"description": "A lightweight, low-overhead concurrency library",
|
5
|
+
"homepage": "https://ciorent.netlify.app",
|
6
|
+
"repository": {
|
7
|
+
"type": "github",
|
8
|
+
"url": "https://github.com/re-utils/ciorent"
|
9
|
+
},
|
10
|
+
"keywords": ["low-overhead", "lightweight", "concurrency", "cross-runtime"],
|
11
|
+
"license": "MIT",
|
12
|
+
"type": "module",
|
13
|
+
"main": "./index.js",
|
14
|
+
"types": "./index.d.ts",
|
15
|
+
"exports": {
|
16
|
+
"./queue": "./queue.js",
|
17
|
+
"./fiber": "./fiber.js",
|
18
|
+
".": "./index.js",
|
19
|
+
"./semaphore": "./semaphore.js",
|
20
|
+
"./stream": "./stream.js"
|
21
|
+
}
|
28
22
|
}
|
package/queue.d.ts
CHANGED
@@ -1,24 +1,19 @@
|
|
1
1
|
/**
|
2
|
-
|
3
|
-
|
2
|
+
* @module Queue utilities
|
3
|
+
*/
|
4
4
|
/**
|
5
|
-
|
6
|
-
|
7
|
-
export type FixedQueue<T extends {} = {}> = [
|
8
|
-
buffer: (T | undefined | null)[],
|
9
|
-
capacity: number,
|
10
|
-
head: number,
|
11
|
-
tail: number
|
12
|
-
];
|
5
|
+
* Describe a fixed-sized queue
|
6
|
+
*/
|
7
|
+
export type FixedQueue<T extends {} = {}> = [buffer: (T | undefined | null)[], capacity: number, head: number, tail: number];
|
13
8
|
/**
|
14
|
-
|
15
|
-
|
9
|
+
* Describe a queue node (singly linked list node)
|
10
|
+
*/
|
16
11
|
export type QueueNode<T> = [next: QueueNode<T> | null, value: T];
|
17
12
|
/**
|
18
|
-
|
19
|
-
|
13
|
+
* Describe an unbounded queue
|
14
|
+
*/
|
20
15
|
export type UnboundedQueue<T> = [head: QueueNode<T>, tail: QueueNode<T>];
|
21
16
|
/**
|
22
|
-
|
23
|
-
|
17
|
+
* Cached promise callback
|
18
|
+
*/
|
24
19
|
export type PromiseFn<T = any> = (res: (value?: T) => void) => void;
|
package/queue.js
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
export{};
|
package/semaphore.d.ts
CHANGED
@@ -1,28 +1,24 @@
|
|
1
1
|
/**
|
2
|
-
|
3
|
-
|
4
|
-
import type { PromiseFn, UnboundedQueue } from
|
2
|
+
* @module Semaphores
|
3
|
+
*/
|
4
|
+
import type { PromiseFn, UnboundedQueue } from "./queue.js";
|
5
5
|
/**
|
6
|
-
|
7
|
-
|
8
|
-
export type Semaphore = [
|
9
|
-
...UnboundedQueue<() => void>,
|
10
|
-
callback: PromiseFn<void>,
|
11
|
-
remain: number
|
12
|
-
];
|
6
|
+
* Describe a semaphore
|
7
|
+
*/
|
8
|
+
export type Semaphore = [...UnboundedQueue<() => void>, callback: PromiseFn<void>, remain: number];
|
13
9
|
/**
|
14
|
-
|
15
|
-
|
10
|
+
* Create a semaphore that allows n accesses
|
11
|
+
*/
|
16
12
|
export declare const init: (n: number) => Semaphore;
|
17
13
|
/**
|
18
|
-
|
19
|
-
|
14
|
+
* Wait until the semaphore allows access
|
15
|
+
*/
|
20
16
|
export declare const acquire: (s: Semaphore) => Promise<void>;
|
21
17
|
/**
|
22
|
-
|
23
|
-
|
18
|
+
* Signal to the semaphore to release access
|
19
|
+
*/
|
24
20
|
export declare const release: (s: Semaphore) => void;
|
25
21
|
/**
|
26
|
-
|
27
|
-
|
22
|
+
* Bind a task to a semaphore
|
23
|
+
*/
|
28
24
|
export declare const bind: <T extends (...args: any[]) => Promise<any>>(f: T, s: Semaphore) => T;
|
package/semaphore.js
CHANGED
@@ -1 +1 @@
|
|
1
|
-
export let init=
|
1
|
+
export let init=e=>{let n=[null],r=[n,n,e=>{r[0]=r[0][0]=[null,e]},e];return r};export let acquire=async e=>{if(e[3]--,e[3]<0)return new Promise(e[2])};export let release=e=>{e[3]<0&&(e[1]=e[1][0])[1](),e[3]++};export let bind=(e,n)=>async(...r)=>{n[3]--,n[3]<0&&await new Promise(n[2]);try{return await e(...r)}finally{n[3]<0&&(n[1]=n[1][0])[1](),n[3]++}};
|
package/stream.d.ts
CHANGED
@@ -1,31 +1,27 @@
|
|
1
1
|
/**
|
2
|
-
|
3
|
-
|
4
|
-
import type { PromiseFn, UnboundedQueue } from
|
2
|
+
* @module Streams
|
3
|
+
*/
|
4
|
+
import type { PromiseFn, UnboundedQueue } from "./queue.js";
|
5
5
|
/**
|
6
|
-
|
7
|
-
|
8
|
-
export type Stream<T extends {} = {}> = [
|
9
|
-
...UnboundedQueue<T | ((val?: T) => void)>,
|
10
|
-
callback: PromiseFn<T>,
|
11
|
-
queueing: boolean
|
12
|
-
];
|
6
|
+
* Describe a stream
|
7
|
+
*/
|
8
|
+
export type Stream<T extends {} = {}> = [...UnboundedQueue<T | ((val?: T) => void)>, callback: PromiseFn<T>, queueing: boolean];
|
13
9
|
/**
|
14
|
-
|
15
|
-
|
10
|
+
* Create a stream
|
11
|
+
*/
|
16
12
|
export declare const init: <T extends {} = {}>() => Stream<T>;
|
17
13
|
/**
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
14
|
+
* Write a value to the stream
|
15
|
+
* @param s
|
16
|
+
* @param v
|
17
|
+
*/
|
22
18
|
export declare const write: <T extends {} = {}>(s: Stream<T>, v: T) => void;
|
23
19
|
/**
|
24
|
-
|
25
|
-
|
26
|
-
|
20
|
+
* Read a value from the stream
|
21
|
+
* @param s
|
22
|
+
*/
|
27
23
|
export declare const read: <T extends {} = {}>(s: Stream<T>) => Promise<T | undefined>;
|
28
24
|
/**
|
29
|
-
|
30
|
-
|
25
|
+
* Release all pending read with undefined
|
26
|
+
*/
|
31
27
|
export declare const flush: (s: Stream) => void;
|
package/stream.js
CHANGED
@@ -1 +1 @@
|
|
1
|
-
export let init=()=>{let
|
1
|
+
export let init=()=>{let e=[null],r=[e,e,e=>{r[0]=r[0][0]=[null,e]},!1];return r};export let write=(e,r)=>{if(!e[3]){if(e[1][0]!==null){(e[1]=e[1][0])[1](r);return}e[3]=!0}e[0]=e[0][0]=[null,r]};export let read=async e=>e[3]?(e[1]=e[1][0],e[1][0]===null&&(e[3]=!1),e[1][1]):new Promise(e[2]);export let flush=e=>{if(!e[3])for(;e[1][0]!==null;)(e[1]=e[1][0])[1]()};
|
package/topic.d.ts
DELETED
@@ -1,45 +0,0 @@
|
|
1
|
-
/**
|
2
|
-
* @module Pubsub
|
3
|
-
*/
|
4
|
-
import type { PromiseFn, QueueNode } from './queue.js';
|
5
|
-
/**
|
6
|
-
* Describe a topic
|
7
|
-
*/
|
8
|
-
export type Topic<T extends {} = {}> = [
|
9
|
-
head: QueueNode<T>,
|
10
|
-
callback: PromiseFn<void>,
|
11
|
-
resolve: (() => void) | null,
|
12
|
-
pending: Promise<void> | null
|
13
|
-
];
|
14
|
-
/**
|
15
|
-
* Describe a subscriber
|
16
|
-
*/
|
17
|
-
export type Subscriber<T extends {} = {}> = [
|
18
|
-
topic: Topic<T>,
|
19
|
-
tail: QueueNode<T>
|
20
|
-
];
|
21
|
-
/**
|
22
|
-
* Create a topic
|
23
|
-
*/
|
24
|
-
export declare const init: <T extends {} = {}>() => Topic<T>;
|
25
|
-
/**
|
26
|
-
* Publish a message to the topic
|
27
|
-
* @param t - The topic
|
28
|
-
* @param m - The message to publish
|
29
|
-
*/
|
30
|
-
export declare const publish: <T extends {} = {}>(t: Topic<T>, m: T) => void;
|
31
|
-
/**
|
32
|
-
* Resolve all pending dispatch
|
33
|
-
*/
|
34
|
-
export declare const flush: (t: Topic) => void;
|
35
|
-
/**
|
36
|
-
* Subscribe to a topic
|
37
|
-
* @param t
|
38
|
-
* @returns A subscriber object
|
39
|
-
*/
|
40
|
-
export declare const subscribe: <T extends {}>(t: Topic<T>) => Subscriber<T>;
|
41
|
-
/**
|
42
|
-
* Wait for messages from the topic
|
43
|
-
* @param s
|
44
|
-
*/
|
45
|
-
export declare const dispatch: <T extends {}>(s: Subscriber<T>) => Promise<T | undefined>;
|
package/topic.js
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
export let init=()=>{let t=[[null],(res)=>{t[2]=res},null,null];return t};export let publish=(t,m)=>{t[0]=t[0][0]=[null,m];t[2]?.();t[2]=null};export let flush=publish;export let subscribe=(t)=>[t,t[0]];export let dispatch=async(s)=>{if(s[1][0]===null)await(s[0][2]!==null?s[0][3]:s[0][3]=new Promise(s[0][1]));return(s[1]=s[1][0])[1]};
|