ciorent 0.0.16 → 0.0.18

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
@@ -23,47 +23,77 @@ const task = semaphore.task(
23
23
  cio.concurrent(6, task);
24
24
  ```
25
25
 
26
- ## Latch
27
- Latch is a synchronization primitive that allows one process to wait until another completes an operation before continuing execution.
26
+ ## Fibers
27
+ Virtual threads with more controlled execution.
28
28
 
29
29
  ```ts
30
- import * as latch from 'ciorent/latch';
31
30
  import * as cio from 'ciorent';
31
+ import * as fiber from 'ciorent/fiber';
32
32
 
33
- const fetchLatch = latch.init();
33
+ function* thread1() {
34
+ console.log('Fiber 1 started');
35
+ yield;
36
+ console.log('Fiber 1 done');
37
+ }
34
38
 
35
- const task = async () => {
36
- // Blocks until the latch is open
37
- await latch.pause(fetchLatch);
39
+ function* thread2() {
40
+ console.log('Fiber 2 started');
38
41
 
39
- const res = await fetch('http://example.com');
40
- console.log('Fetch status:', res.status);
41
- }
42
+ yield;
43
+ console.log('Fiber 2 resumed');
42
44
 
43
- const prepare = () => {
44
- console.log('Run before fetch:', performance.now().toFixed(2));
45
+ // Wait for a promise
46
+ yield* fiber.wait(cio.sleep(1000));
47
+ console.log('Fiber 2 waited for 1s');
48
+
49
+ // Start task 1 and wait for it to be done
50
+ yield* fiber.join(
51
+ fiber.start(thread1())
52
+ );
53
+
54
+ console.log('Fiber 2 done');
45
55
  }
46
56
 
47
- const main = async () => {
48
- const p = task();
49
- await cio.sleep(500);
50
- prepare();
57
+ // Start running the thread
58
+ fiber.start(thread2());
59
+ ```
51
60
 
52
- // Allows all previously blocked tasks to run
53
- latch.open(fetchLatch);
61
+ ## Channel
62
+ 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.
54
63
 
55
- // Reclose the latch
56
- // Tasks that aren't blocked yet will be blocked
57
- latch.reset(fetchLatch);
64
+ ```ts
65
+ import * as channel from 'ciorent/channel';
66
+ import * as cio from 'ciorent';
58
67
 
59
- return p;
68
+ const c = channel.init<number>();
69
+
70
+ const run = async () => {
71
+ for (let i = 0; i < 10; i++) {
72
+ await cio.sleep(10);
73
+ channel.send(c, i);
74
+ console.log('Sent', i);
75
+ }
76
+
77
+ // Resolve all waiting promises with `undefined`
78
+ // This is a way to tell the reciever to not listen to more data
79
+ channel.flush(c);
80
+ };
81
+
82
+ const log = async () => {
83
+ while (true) {
84
+ // Wait until a value is sent
85
+ const x = await channel.recieve(c);
86
+ if (x == null) break;
87
+
88
+ console.log('Recieved', x);
89
+ };
60
90
  }
61
91
 
62
- // Run fetch after 500ms
63
- await main();
92
+ run();
93
+ log();
64
94
 
65
- // Run fetch after another 500ms
66
- await main();
95
+ // This runs first
96
+ console.log('Starting...');
67
97
  ```
68
98
 
69
99
  ## Pubsub
@@ -102,42 +132,47 @@ cio.concurrent(5, async (id: number) => {
102
132
  publisher();
103
133
  ```
104
134
 
105
- ## Channel
106
- 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.
135
+ ## Latch
136
+ Latch is a synchronization primitive that allows one process to wait until another completes an operation before continuing execution.
107
137
 
108
138
  ```ts
109
- import * as channel from 'ciorent/channel';
139
+ import * as latch from 'ciorent/latch';
110
140
  import * as cio from 'ciorent';
111
141
 
112
- const c = channel.init<number>();
142
+ const fetchLatch = latch.init();
113
143
 
114
- const run = async () => {
115
- for (let i = 0; i < 10; i++) {
116
- await cio.sleep(10);
117
- channel.send(c, i);
118
- console.log('Sent', i);
119
- }
144
+ const task = async () => {
145
+ // Blocks until the latch is open
146
+ await latch.pause(fetchLatch);
120
147
 
121
- // Resolve all waiting promises with `undefined`
122
- // This is a way to tell the reciever to not listen to more data
123
- channel.flush(c);
124
- };
148
+ const res = await fetch('http://example.com');
149
+ console.log('Fetch status:', res.status);
150
+ }
125
151
 
126
- const log = async () => {
127
- while (true) {
128
- // Wait until a value is sent
129
- const x = await channel.recieve(c);
130
- if (x == null) break;
152
+ const prepare = () => {
153
+ console.log('Run before fetch:', performance.now().toFixed(2));
154
+ }
131
155
 
132
- console.log('Recieved', x);
133
- };
156
+ const main = async () => {
157
+ const p = task();
158
+ await cio.sleep(500);
159
+ prepare();
160
+
161
+ // Allows all previously blocked tasks to run
162
+ latch.open(fetchLatch);
163
+
164
+ // Reclose the latch
165
+ // Tasks that aren't blocked yet will be blocked
166
+ latch.reset(fetchLatch);
167
+
168
+ return p;
134
169
  }
135
170
 
136
- run();
137
- log();
171
+ // Run fetch after 500ms
172
+ await main();
138
173
 
139
- // This runs first
140
- console.log('Starting...');
174
+ // Run fetch after another 500ms
175
+ await main();
141
176
  ```
142
177
 
143
178
  ## Utilities
@@ -174,10 +209,13 @@ task2();
174
209
  ### Sleep
175
210
  A cross-runtime sleep function.
176
211
  ```ts
177
- import { sleep } from 'ciorent';
212
+ import { sleep, sleepSync } from 'ciorent';
178
213
 
179
214
  await sleep(500);
180
215
  console.log('Hi');
216
+
217
+ sleepSync(500);
218
+ console.log('Hi');
181
219
  ```
182
220
 
183
221
  ### Spawning tasks
package/channel.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * @module Channels
3
3
  */
4
- import type { QueueNode } from './fixed-queue';
4
+ import type { QueueNode } from './fixed-queue.js';
5
5
  /**
6
6
  * Describe a channel
7
7
  */
@@ -1,9 +1,9 @@
1
1
  /**
2
2
  * @module Dropping queues
3
3
  */
4
- import type { FixedQueue } from './fixed-queue';
5
- export { init } from './fixed-queue';
6
- export { pop } from './sliding-queue';
4
+ import type { FixedQueue } from './fixed-queue.js';
5
+ export { init } from './fixed-queue.js';
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
package/dropping-queue.js CHANGED
@@ -1 +1 @@
1
- export{init}from"./fixed-queue";export{pop}from"./sliding-queue";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{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};
@@ -0,0 +1,74 @@
1
+ /**
2
+ * @module Fiber
3
+ */
4
+ /**
5
+ * When the fiber is paused
6
+ */
7
+ export declare const paused: (t: Thread) => boolean;
8
+ /**
9
+ * When the fiber is running
10
+ */
11
+ export declare const running: (t: Thread) => boolean;
12
+ /**
13
+ * When the fiber is done
14
+ */
15
+ export declare const done: (t: Thread) => boolean;
16
+ /**
17
+ * Describe a fiber
18
+ */
19
+ export interface Thread<T = unknown, TReturn = unknown> {
20
+ /**
21
+ * The original generator
22
+ */
23
+ 0: Generator<T, TReturn>;
24
+ /**
25
+ * The waiting promise
26
+ */
27
+ 1: Promise<T | TReturn>;
28
+ /**
29
+ * Fiber status
30
+ */
31
+ 2: 0 | 1 | 2;
32
+ /**
33
+ * Callback to continue running the fiber
34
+ */
35
+ 3: null | (() => void);
36
+ }
37
+ /**
38
+ * Describe a fiber runtime
39
+ */
40
+ export type Runtime = <const T, const TReturn>(gen: Generator<T, TReturn>) => Thread<T, TReturn>;
41
+ /**
42
+ * A basic fiber runtime
43
+ * @param g
44
+ */
45
+ export declare const start: Runtime;
46
+ /**
47
+ * Pause the execution of a fiber
48
+ * @param t
49
+ */
50
+ export declare const pause: (t: Thread) => void;
51
+ /**
52
+ * Resume the execution of a fiber
53
+ * @param t
54
+ */
55
+ export declare const resume: (t: Thread) => void;
56
+ /**
57
+ * Stop the execution of a fiber and retrieve the result
58
+ * @param t
59
+ */
60
+ export declare const stop: <T extends Thread>(t: T) => T[1];
61
+ /**
62
+ * Wait for a fiber and retrieve its result
63
+ * @param t
64
+ */
65
+ export declare function join<T extends Thread>(t: T): Generator<Awaited<T[1]>, Awaited<T[1]>>;
66
+ /**
67
+ * Wait for a fiber to finish and retrieve its result
68
+ * @param t
69
+ */
70
+ export declare const finish: <T extends Thread>(t: T) => T[1];
71
+ /**
72
+ * Wait for a promise to resolve then retrieve its result
73
+ */
74
+ export declare function wait<T extends Promise<any>>(t: T): Generator<Awaited<T>, Awaited<T>>;
package/fiber/index.js ADDED
@@ -0,0 +1 @@
1
+ export let paused=(t)=>t[2]===0;export let running=(t)=>t[2]===1;export let done=(t)=>t[2]===2;let invoke=async(g,thread)=>{let t=g.next();while(!t.done){let v=await t.value;if(thread[2]===0){let r;let p=new Promise((res)=>{r=res});thread[3]=r;await p}if(thread[2]===2)return v;t=g.next(v)}thread[2]=2;return t.value};export let start=(g)=>{let thread=[g,null,1,null];thread[1]=invoke(g,thread);return thread};export let pause=(t)=>{if(t[2]===1)t[2]=0};export let resume=(t)=>{if(t[2]===0){t[2]=1;t[3]?.()}};export let stop=(t)=>{if(t[2]===0){t[2]=2;t[3]()}else t[2]=2;return t[1]};export function*join(t){return yield t[1]}export let finish=(t)=>t[1];export function*wait(t){return yield t}
package/fixed-queue.d.ts CHANGED
@@ -26,10 +26,7 @@ export interface FixedQueue<T extends {}> {
26
26
  /**
27
27
  * Describe a queue node (singly linked list node)
28
28
  */
29
- export type QueueNode<T> = [
30
- value: T,
31
- next: QueueNode<T> | null
32
- ];
29
+ export type QueueNode<T> = [value: T, next: QueueNode<T> | null];
33
30
  /**
34
31
  * Create a fixed queue.
35
32
  * @param n - The queue size
package/index.d.ts CHANGED
@@ -14,6 +14,13 @@ export declare const pause: Promise<void>;
14
14
  * @param ms - Sleep duration in milliseconds
15
15
  */
16
16
  export declare const sleep: (ms: number) => Promise<void>;
17
+ /**
18
+ * Sleep for a duration synchronously.
19
+ *
20
+ * On the browser it only works in workers.
21
+ * @param ms - Sleep duration in milliseconds
22
+ */
23
+ export declare const sleepSync: (ms: number) => void;
17
24
  /**
18
25
  * Spawn n tasks that runs sequentially
19
26
  * @param n
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)}));export let sequential=async(n,task)=>{for(let i=0;i<n;i++)await task(i)};export let concurrent=(n,task)=>{let arr=new Array(n);for(let i=0;i<n;i++)arr[i]=task(i);return Promise.all(arr)};
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)=>{for(let i=0;i<n;i++)await task(i)};export let concurrent=(n,task)=>{let arr=new Array(n);for(let i=0;i<n;i++)arr[i]=task(i);return Promise.all(arr)};
package/latch.d.ts CHANGED
@@ -4,10 +4,7 @@
4
4
  /**
5
5
  * Describe a latch
6
6
  */
7
- export type Latch = [
8
- pause: Promise<void>,
9
- open: () => void
10
- ];
7
+ export type Latch = [pause: Promise<void>, open: () => void];
11
8
  /**
12
9
  * Create a latch
13
10
  */
package/latch.js CHANGED
@@ -1 +1 @@
1
- import{pause as endPromise}from".";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 reset=(latch)=>{if(latch[0]===endPromise){let r;latch[0]=new Promise((res)=>{r=res});latch[1]=r}};
1
+ import{pause 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 reset=(latch)=>{if(latch[0]===endPromise){let r;latch[0]=new Promise((res)=>{r=res});latch[1]=r}};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ciorent",
3
- "version": "0.0.16",
3
+ "version": "0.0.18",
4
4
  "description": "A lightweight, low-overhead concurrency library",
5
5
  "homepage": "https://ciorent.netlify.app",
6
6
  "repository": {
@@ -17,27 +17,16 @@
17
17
  "type": "module",
18
18
  "main": "./index.js",
19
19
  "types": "./index.d.ts",
20
- "scripts": {
21
- "task": "bun scripts/task.ts",
22
- "build:test": "bun task build && bun docs && bun test",
23
- "build:publish": "bun build:test && bun task report-size && bun task publish",
24
- "lint": "eslint ./src",
25
- "lint:fix": "eslint ./src --fix",
26
- "docs": "typedoc"
27
- },
28
- "devDependencies": {
29
- "@stylistic/eslint-plugin": "latest",
30
- "@types/bun": "latest",
31
- "@types/uglify-js": "latest",
32
- "eslint": "latest",
33
- "eslint-plugin-jsdoc": "latest",
34
- "mitata": "latest",
35
- "terser": "^5.39.0",
36
- "tsx": "latest",
37
- "typedoc": "^0.27.9",
38
- "typedoc-material-theme": "^1.3.0",
39
- "typedoc-plugin-inline-sources": "^1.2.1",
40
- "typescript": "latest",
41
- "typescript-eslint": "latest"
20
+ "exports": {
21
+ "./fixed-queue": "./fixed-queue.js",
22
+ "./sliding-queue": "./sliding-queue.js",
23
+ ".": "./index.js",
24
+ "./dropping-queue": "./dropping-queue.js",
25
+ "./semaphore": "./semaphore.js",
26
+ "./channel": "./channel.js",
27
+ "./fiber": "./fiber/index.js",
28
+ "./latch": "./latch.js",
29
+ "./concurrent": "./concurrent.d.ts",
30
+ "./topic": "./topic.js"
42
31
  }
43
- }
32
+ }
package/semaphore.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * @module Semaphores
3
3
  */
4
- import type { QueueNode } from './fixed-queue';
4
+ import type { QueueNode } from './fixed-queue.js';
5
5
  /**
6
6
  * Describe a semaphore
7
7
  */
@@ -34,7 +34,7 @@ export declare const signal: (s: Semaphore) => void;
34
34
  /**
35
35
  * Wrap a task to bind to a custom semaphore later
36
36
  */
37
- export declare const wrap: <Args extends any[], Return extends Promise<any>>(f: (...args: Args) => Return) => (s: Semaphore, ...a: Args) => Return;
37
+ export declare const wrap: <Args extends any[], Return extends Promise<any>>(f: (...args: Args) => Return) => ((s: Semaphore, ...a: Args) => Return);
38
38
  /**
39
39
  * Create a task that acquire a semaphore and release the access when it's finished
40
40
  */
package/semaphore.js CHANGED
@@ -1 +1 @@
1
- import{pause as resolvedPromise}from".";export let init=(n)=>{let root=[null,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][1]=[r,null];return p}return resolvedPromise};export let signal=(s)=>{if(s[0]<0)(s[2]=s[2][1])[0]();s[0]++};export let wrap=(f)=>async(s,...a)=>{s[0]--;if(s[0]<0){let r;let p=new Promise((res)=>{r=res});s[1]=s[1][1]=[r,null];await p}try{return await f(...a)}finally{signal(s)}};export let task=(s,f)=>{f=wrap(f);return(...a)=>f(s,...a)};
1
+ import{pause as resolvedPromise}from"./index.js";export let init=(n)=>{let root=[null,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][1]=[r,null];return p}return resolvedPromise};export let signal=(s)=>{if(s[0]<0)(s[2]=s[2][1])[0]();s[0]++};export let wrap=(f)=>async(s,...a)=>{s[0]--;if(s[0]<0){let r;let p=new Promise((res)=>{r=res});s[1]=s[1][1]=[r,null];await p}try{return await f(...a)}finally{signal(s)}};export let task=(s,f)=>{f=wrap(f);return(...a)=>f(s,...a)};
@@ -1,8 +1,8 @@
1
1
  /**
2
2
  * @module Sliding queues
3
3
  */
4
- import type { FixedQueue } from './fixed-queue';
5
- export { init } from './fixed-queue';
4
+ import type { FixedQueue } from './fixed-queue.js';
5
+ export { init } from './fixed-queue.js';
6
6
  /**
7
7
  * Push an item to a sliding queue
8
8
  * @param q - The queue to push to
package/sliding-queue.js CHANGED
@@ -1 +1 @@
1
- export{init}from"./fixed-queue";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{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}};
package/topic.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * @module Pubsub
3
3
  */
4
- import type { QueueNode } from './fixed-queue';
4
+ import type { QueueNode } from './fixed-queue.js';
5
5
  /**
6
6
  * Describe a topic
7
7
  */