ciorent 0.1.4 → 0.1.5

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
@@ -1,34 +1,13 @@
1
1
  A lightweight, low-overhead concurrency library.
2
- ## Semaphore
3
- Semaphore is a concurrency primitive used to control access to a common resource by multiple processes.
4
-
5
- ```ts
6
- import * as semaphore from 'ciorent/semaphore';
7
- import * as co from 'ciorent';
8
-
9
- // Only allow 2 task to run concurrently
10
- const sem = semaphore.init(2);
11
2
 
12
- const task = async (id: number) => {
13
- // Acquire the semaphore or wait for the semaphore to be available
14
- await semaphore.pause(sem);
15
-
16
- console.log('Task', id, 'started');
17
-
18
- // Let the main thread schedules other tasks
19
- for (let i = 1; i <= 5; i++) await co.pause;
3
+ ## Features
4
+ - Micro-optimized utilities.
5
+ - Performance-oriented API design.
6
+ - Small bundle size.
7
+ - Fully type-safe.
20
8
 
21
- console.log('Task', id, 'end');
22
-
23
- // Release the semaphore
24
- semaphore.signal(sem);
25
- }
26
-
27
- // Try to run 5 tasks concurrently
28
- co.spawn(5, task);
29
- ```
30
-
31
- ## Fibers
9
+ ## Examples
10
+ ### Fibers
32
11
  Virtual threads with more controlled execution.
33
12
 
34
13
  ```ts
@@ -36,31 +15,57 @@ import * as co from 'ciorent';
36
15
  import * as fiber from 'ciorent/fiber';
37
16
 
38
17
  const f1 = fiber.fn(function* () {
39
- console.log('Fiber 1 started');
40
-
41
18
  // Wait for a promise
42
19
  yield co.sleep(1000);
43
20
 
44
- console.log('Fiber 1 done');
21
+ // Wait for a promise and return its result
22
+ const res = yield* fiber.unwrap(Promise.resolve(1));
23
+ console.log('Fiber 1 recieved:', res);
24
+
45
25
  return Math.random();
46
26
  });
47
27
 
48
- fiber.spawn(function* (proc) {
49
- console.log('Fiber 2 started');
28
+ {
29
+ const main = fiber.spawn(function* (proc) {
30
+ // Start f1, wait for it to finish and get the result
31
+ const res = yield* fiber.join(fiber.spawn(f1));
32
+ console.log('Fiber 2 recieved:', res);
50
33
 
51
- // Start f1, wait for it to finish and get the result
52
- const res = yield* fiber.join(fiber.spawn(f1));
53
- console.log('Fiber 1 result:', res);
34
+ // Start f1 and make its lifetime depends on current fiber
35
+ const childProc = fiber.spawn(f1);
36
+ fiber.mount(childProc, proc);
37
+ });
54
38
 
55
- // Start f1 and make its lifetime depends on current fiber
56
- fiber.mount(fiber.spawn(f1), proc);
39
+ console.log('Fiber 2 started:', fiber.resumed(main));
57
40
 
58
- // The runtime will interrupt f1
59
- console.log('Fiber 2 done');
60
- });
41
+ // Pause the current fiber process
42
+ fiber.pause(main);
43
+ console.log('Fiber 2 is paused:', fiber.paused(main));
44
+
45
+ // Resume the fiber
46
+ fiber.resume(main);
47
+ console.log('Fiber 2 is resumed:', fiber.resumed(main));
48
+
49
+ // Wait for the fiber process to finish
50
+ await fiber.done(main);
51
+
52
+ // Check finish status
53
+ console.log('Fiber 2 completed', fiber.completed(main));
54
+ }
55
+
56
+ {
57
+ console.log('------------------------');
58
+
59
+ const main = fiber.spawn(f1);
60
+ console.log('Fiber 1 started:', fiber.resumed(main));
61
+
62
+ // Stop a fiber
63
+ fiber.stop(main);
64
+ console.log('Fiber 1 stopped:', fiber.stopped(main));
65
+ }
61
66
  ```
62
67
 
63
- ## Latch
68
+ ### Latch
64
69
  Latch is a synchronization primitive that allows one process to wait until another completes an operation before continuing execution.
65
70
 
66
71
  ```ts
@@ -87,7 +92,45 @@ task();
87
92
  prepare();
88
93
  ```
89
94
 
90
- ## Pubsub
95
+ ### Channel
96
+ 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.
97
+
98
+ ```ts
99
+ import * as channel from 'ciorent/channel';
100
+ import * as co from 'ciorent';
101
+
102
+ const c = channel.init<number>();
103
+
104
+ const run = async () => {
105
+ for (let i = 0; i < 5; i++) {
106
+ await co.sleep(100);
107
+ channel.send(c, i);
108
+ console.log('Sent', i);
109
+ }
110
+
111
+ // Resolve all waiting promises with `undefined`
112
+ // This is a way to tell the reciever to not listen to more data
113
+ channel.flush(c);
114
+ };
115
+
116
+ const log = async () => {
117
+ while (true) {
118
+ // Wait until a value is sent to the channel
119
+ const x = await channel.recieve(c);
120
+ if (x == null) break;
121
+
122
+ console.log('Recieved', x);
123
+ };
124
+ }
125
+
126
+ log();
127
+ run();
128
+
129
+ // This runs first
130
+ console.log('Starting...');
131
+ ```
132
+
133
+ ### Pubsub
91
134
  A fast, simple publish-subscribe API.
92
135
 
93
136
  ```ts
@@ -123,46 +166,37 @@ co.spawn(3, async (id: number) => {
123
166
  publisher();
124
167
  ```
125
168
 
126
- ## Channel
127
- 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.
169
+ ### Semaphore
170
+ Semaphore is a concurrency primitive used to control access to a common resource by multiple processes.
128
171
 
129
172
  ```ts
130
- import * as channel from 'ciorent/channel';
173
+ import * as semaphore from 'ciorent/semaphore';
131
174
  import * as co from 'ciorent';
132
175
 
133
- const c = channel.init<number>();
176
+ // Only allow 2 task to run concurrently
177
+ const sem = semaphore.init(2);
134
178
 
135
- const run = async () => {
136
- for (let i = 0; i < 5; i++) {
137
- await co.sleep(100);
138
- channel.send(c, i);
139
- console.log('Sent', i);
140
- }
179
+ const task = async (id: number) => {
180
+ // Acquire the semaphore or wait for the semaphore to be available
181
+ await semaphore.pause(sem);
141
182
 
142
- // Resolve all waiting promises with `undefined`
143
- // This is a way to tell the reciever to not listen to more data
144
- channel.flush(c);
145
- };
183
+ console.log('Task', id, 'started');
146
184
 
147
- const log = async () => {
148
- while (true) {
149
- // Wait until a value is sent to the channel
150
- const x = await channel.recieve(c);
151
- if (x == null) break;
185
+ // Let the main thread schedules other tasks
186
+ for (let i = 1; i <= 5; i++) await co.pause;
152
187
 
153
- console.log('Recieved', x);
154
- };
155
- }
188
+ console.log('Task', id, 'end');
156
189
 
157
- log();
158
- run();
190
+ // Release the semaphore
191
+ semaphore.signal(sem);
192
+ }
159
193
 
160
- // This runs first
161
- console.log('Starting...');
194
+ // Try to run 5 tasks concurrently
195
+ co.spawn(5, task);
162
196
  ```
163
197
 
164
- ## Utilities
165
- ### Pausing
198
+ ### Utilities
199
+ #### Pausing
166
200
  Delay the execution of a function for other asynchronous tasks to run.
167
201
  ```ts
168
202
  import * as co from 'ciorent';
@@ -194,7 +228,7 @@ task1();
194
228
  task2();
195
229
  ```
196
230
 
197
- ### Sleep
231
+ #### Sleep
198
232
  Cross-runtime synchronous and asynchronous sleep functions.
199
233
  ```ts
200
234
  import * as co from 'ciorent';
@@ -213,7 +247,7 @@ co.sleepSync(500);
213
247
  logTime('After another 0.5s');
214
248
  ```
215
249
 
216
- ### Spawning tasks
250
+ #### Spawning tasks
217
251
  Utilities to create and run tasks.
218
252
  ```ts
219
253
  import * as co from 'ciorent';
@@ -232,7 +266,7 @@ console.log('Running 5 tasks concurrently:');
232
266
  await Promise.all(co.spawn(5, task));
233
267
  ```
234
268
 
235
- ### Debounce
269
+ #### Debounce
236
270
  Postpones execution until after an idle period.
237
271
  ```ts
238
272
  import * as co from 'ciorent';
@@ -246,24 +280,7 @@ await co.sleep(100);
246
280
  fn(2); // fn(2) gets executed
247
281
  ```
248
282
 
249
- ### Rate Limit
250
- Limits the number of calls within a time window.
251
- ```ts
252
- import * as co from 'ciorent';
253
-
254
- // Allow 2 calls in 500ms, other calls are dropped
255
- const fn = co.rateLimit((id: number) => {
256
- console.log('Call ' + id + ':', Math.floor(performance.now()) + 'ms');
257
- }, 500, 2);
258
-
259
- // Some calls will be dropped
260
- for (let i = 0; i < 8; i++) {
261
- fn(i);
262
- await co.sleep(400);
263
- }
264
- ```
265
-
266
- ### Throttle
283
+ #### Throttle
267
284
  Executes a function at a regular interval.
268
285
  ```ts
269
286
  import * as co from 'ciorent';
package/fiber.d.ts CHANGED
@@ -35,9 +35,9 @@ export declare const paused: (t: Process) => boolean;
35
35
  */
36
36
  export declare const resumed: (t: Process) => boolean;
37
37
  /**
38
- * Check whether the fiber has finished
38
+ * Check whether the fiber has completed
39
39
  */
40
- export declare const done: (t: Process) => boolean;
40
+ export declare const completed: (t: Process) => boolean;
41
41
  /**
42
42
  * Check whether the fiber has been interrupted
43
43
  */
@@ -76,7 +76,7 @@ export declare function join<T extends Process>(t: T): Generator<Awaited<T[0]>,
76
76
  * Wait for a fiber to finish and retrieve its result
77
77
  * @param t
78
78
  */
79
- export declare const finish: <T extends Process>(t: T) => T[3];
79
+ export declare const done: <T extends Process>(t: T) => T[0];
80
80
  /**
81
81
  * Mount child fiber lifetime to parent lifetime
82
82
  * @param child
package/fiber.js CHANGED
@@ -1 +1 @@
1
- export let paused=(t)=>t[1]===0;export let resumed=(t)=>t[1]===1;export let done=(t)=>t[1]===2;export let stopped=(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{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 stop=(t)=>{if(t[1]===0)t[2]?.();t[1]=3};export function*join(t){return yield t[0]}export let finish=(t)=>t[3];export let mount=(child,parent)=>{parent[3].push(child)};export let control=(t,signal)=>{signal.addEventListener("abort",()=>{stop(t)})};export function*unwrap(t){return yield t}
1
+ export let paused=(t)=>t[1]===0;export let resumed=(t)=>t[1]===1;export let completed=(t)=>t[1]===2;export let stopped=(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 stop=(t)=>{if(t[1]!==2){if(t[1]===0)t[2]?.();t[1]=3}};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",()=>{stop(t)})};export function*unwrap(t){return yield t}
package/index.d.ts CHANGED
@@ -41,13 +41,6 @@ export declare const spawn: <const T extends any[], const R>(n: number, task: (.
41
41
  * @param ms - The time period in milliseconds
42
42
  */
43
43
  export declare const debounce: <const Args extends any[]>(f: (...args: Args) => any, ms: number) => ((...args: Args) => void);
44
- /**
45
- * Drop function calls for a specific period
46
- * @param f - The target function to rate limit (it must not throw errors)
47
- * @param ms - The time period in milliseconds
48
- * @param limit - The call limit in the time period
49
- */
50
- export declare const rateLimit: <const Args extends any[]>(f: (...args: Args) => any, ms: number, limit: number) => ((...args: Args) => void);
51
44
  /**
52
45
  * Throttle function execution for a time period
53
46
  * @param f - The function to throttle (it must not throw errors)
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 rateLimit=(f,ms,limit)=>{let cur=limit;let unlock=()=>{cur=limit};return(...a)=>{if(cur>0){if(cur===1)setTimeout(unlock,ms);cur--;f(...a)}}};export let throttle=(f,ms,limit)=>{let head=[null];let tail=head;let cur=limit;let unlock=()=>{cur=limit;while(cur>0){if(tail===head)return;cur--;tail=tail[0];tail[1](f(...tail[2]))}setTimeout(unlock,ms)};return(...a)=>{if(cur===1){setTimeout(unlock,ms)}else if(cur===0){let r;let p=new Promise((res)=>{r=res});head=head[0]=[null,r,a];return p}cur--;return f(...a)}};
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=(f,ms,limit)=>{let head=[null];let tail=head;let cur=limit;let scheduled=false;let unlock=()=>{cur=limit;while(cur>0){if(tail===head){scheduled=false;return}cur--;tail=tail[0];tail[1](f(...tail[2]))}setTimeout(unlock,ms)};return(...a)=>{if(cur===0){let r;let p=new Promise((res)=>{r=res});head=head[0]=[null,r,a];return p}if(!scheduled){scheduled=true;setTimeout(unlock,ms)}cur--;return f(...a)}};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ciorent",
3
- "version": "0.1.4",
3
+ "version": "0.1.5",
4
4
  "description": "A lightweight, low-overhead concurrency library",
5
5
  "homepage": "https://ciorent.netlify.app",
6
6
  "repository": {
@@ -19,13 +19,13 @@
19
19
  "types": "./index.d.ts",
20
20
  "exports": {
21
21
  "./fixed-queue": "./fixed-queue.js",
22
- "./dropping-queue": "./dropping-queue.js",
23
22
  "./sliding-queue": "./sliding-queue.js",
24
- ".": "./index.js",
25
- "./topic": "./topic.js",
26
- "./semaphore": "./semaphore.js",
23
+ "./latch": "./latch.js",
27
24
  "./channel": "./channel.js",
28
25
  "./fiber": "./fiber.js",
29
- "./latch": "./latch.js"
26
+ "./dropping-queue": "./dropping-queue.js",
27
+ ".": "./index.js",
28
+ "./topic": "./topic.js",
29
+ "./semaphore": "./semaphore.js"
30
30
  }
31
31
  }