ciorent 0.3.8 → 0.4.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
@@ -118,7 +118,7 @@ Pubsub allows broadcasting messages to topics that can be recieved by subscriber
118
118
  import * as topic from 'ciorent/topic';
119
119
  import * as co from 'ciorent';
120
120
 
121
- const numbers = topic.init();
121
+ const numbers = topic.init<number>();
122
122
 
123
123
  // Spawn 3 tasks that subscribe to the topic
124
124
  co.spawn(3, async (id) => {
@@ -141,43 +141,14 @@ for (let i = 0; i < 3; i++) {
141
141
  topic.flush(numbers);
142
142
  ```
143
143
 
144
- ### Semaphore
145
- Semaphore is a concurrency primitive used to control access to a common resource by multiple processes.
146
-
147
- ```ts
148
- import * as semaphore from 'ciorent/semaphore';
149
- import * as co from 'ciorent';
150
-
151
- // Only allow 2 task to run concurrently
152
- const sem = semaphore.init(2);
153
-
154
- const task = async (id: number) => {
155
- // Acquire the semaphore or wait for the semaphore to be available
156
- await semaphore.acquire(sem);
157
-
158
- console.log('Task', id, 'started');
159
-
160
- // Let the main thread schedules other tasks
161
- for (let i = 1; i <= 5; i++) await co.nextTick;
162
-
163
- console.log('Task', id, 'end');
164
-
165
- // Release the semaphore
166
- semaphore.release(sem);
167
- }
168
-
169
- // Try to run 5 tasks concurrently
170
- co.spawn(5, task);
171
- ```
172
-
173
- ### Pubsub
174
- Pubsub allows broadcasting messages to topics that can be recieved by subscribers.
144
+ ### Stream
145
+ Send and recieve data asynchronously through streams.
175
146
 
176
147
  ```ts
177
148
  import * as stream from 'ciorent/stream';
178
149
  import * as co from 'ciorent';
179
150
 
180
- const numbers = stream.init();
151
+ const numbers = stream.init<number>();
181
152
 
182
153
  // Spawn 3 tasks that read from the stream
183
154
  co.spawn(3, async (id) => {
@@ -198,33 +169,33 @@ for (let i = 0; i < 3; i++) {
198
169
  stream.flush(numbers);
199
170
  ```
200
171
 
201
- ### Defer
202
- Wait for a value to be resolved.
172
+ ### Semaphore
173
+ Semaphore is a concurrency primitive used to control access to a common resource by multiple processes.
203
174
 
204
175
  ```ts
205
- import * as defer from 'ciorent/defer';
176
+ import * as semaphore from 'ciorent/semaphore';
177
+ import * as co from 'ciorent';
206
178
 
207
- const logTime = (label: string) => console.log(`${label}: ${Math.floor(performance.now())}ms`);
179
+ // Only allow 2 task to run concurrently
180
+ const sem = semaphore.init(2);
208
181
 
209
- const deferredUrl = defer.init<string>();
182
+ const task = async (id: number) => {
183
+ // Acquire the semaphore or wait for the semaphore to be available
184
+ await semaphore.acquire(sem);
210
185
 
211
- const task = async () => {
212
- // Blocks until the defer is resolved
213
- const url = await defer.wait(deferredUrl);
186
+ console.log('Task', id, 'started');
214
187
 
215
- logTime('Start fetching');
216
- await fetch(url).catch(() => {});
217
- logTime('Done fetching');
218
- }
188
+ // Let the main thread schedules other tasks
189
+ for (let i = 1; i <= 5; i++) await co.nextTick;
219
190
 
220
- const prepare = () => {
221
- // This always run first as task is waiting
222
- logTime('Run before fetch');
223
- defer.resolve(deferredUrl, 'http://localhost:3000');
191
+ console.log('Task', id, 'end');
192
+
193
+ // Release the semaphore
194
+ semaphore.release(sem);
224
195
  }
225
196
 
226
- task();
227
- prepare();
197
+ // Try to run 5 tasks concurrently
198
+ co.spawn(5, task);
228
199
  ```
229
200
 
230
201
  ### Fibers
package/fiber.d.ts CHANGED
@@ -5,21 +5,9 @@
5
5
  * Describe a fiber process
6
6
  */
7
7
  export type Process<TReturn = unknown> = [
8
- /**
9
- * The waiting promise
10
- */
11
8
  proc: Promise<TReturn | undefined>,
12
- /**
13
- * Fiber status
14
- */
15
9
  status: 0 | 1 | 2 | 3,
16
- /**
17
- * Callback to resume the fiber
18
- */
19
10
  resume: null | ((state: 1 | 3) => void),
20
- /**
21
- * Bounded fibers
22
- */
23
11
  children: Process[]
24
12
  ];
25
13
  /**
package/index.js CHANGED
@@ -1 +1 @@
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 promiseCb=(res)=>{head=head[0]=[null,res]};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(promiseCb);if(!scheduled){scheduled=true;setTimeout(unlock,ms)}cur--;return nextTick}};
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 promiseCb=(res)=>{head=head[0]=[null,res]};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 async()=>{if(cur===0)return new Promise(promiseCb);if(!scheduled){scheduled=true;setTimeout(unlock,ms)}cur--}};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ciorent",
3
- "version": "0.3.8",
3
+ "version": "0.4.0",
4
4
  "description": "A lightweight, low-overhead concurrency library",
5
5
  "homepage": "https://ciorent.netlify.app",
6
6
  "repository": {
@@ -18,15 +18,11 @@
18
18
  "main": "./index.js",
19
19
  "types": "./index.d.ts",
20
20
  "exports": {
21
- "./queue": "./queue.js",
22
- "./sliding-queue": "./sliding-queue.js",
23
- "./dropping-queue": "./dropping-queue.js",
21
+ "./fiber": "./fiber.js",
22
+ "./queue": "./queue.d.ts",
24
23
  "./semaphore": "./semaphore.js",
25
- "./lock": "./lock.js",
26
- "./defer": "./defer.js",
27
- ".": "./index.js",
28
24
  "./stream": "./stream.js",
29
25
  "./topic": "./topic.js",
30
- "./fiber": "./fiber.js"
26
+ ".": "./index.js"
31
27
  }
32
28
  }
package/queue.d.ts CHANGED
@@ -4,30 +4,21 @@
4
4
  /**
5
5
  * Describe a fixed-sized queue
6
6
  */
7
- export type Fixed<T extends {} = {}> = [
8
- /**
9
- * Pre-allocated queue
10
- */
7
+ export type FixedQueue<T extends {} = {}> = [
11
8
  buffer: (T | undefined | null)[],
12
- /**
13
- * Queue capacity
14
- */
15
9
  capacity: number,
16
- /**
17
- * Head pointer
18
- */
19
10
  head: number,
20
- /**
21
- * Tail pointer
22
- */
23
11
  tail: number
24
12
  ];
25
13
  /**
26
14
  * Describe a queue node (singly linked list node)
27
15
  */
28
- export type Node<T> = [next: Node<T> | null, value: T];
16
+ export type QueueNode<T> = [next: QueueNode<T> | null, value: T];
29
17
  /**
30
- * Create a fixed queue
31
- * @param n - The queue size
18
+ * Describe an unbounded queue
32
19
  */
33
- export declare const fixed: <T extends {} = {}>(n: number) => Fixed<T>;
20
+ export type UnboundedQueue<T> = [head: QueueNode<T>, tail: QueueNode<T>];
21
+ /**
22
+ * Cached promise callback
23
+ */
24
+ export type PromiseFn<T = any> = (res: (value?: T) => void) => void;
package/semaphore.d.ts CHANGED
@@ -1,16 +1,15 @@
1
1
  /**
2
2
  * @module Semaphores
3
3
  */
4
- import { type Lock } from './lock.js';
4
+ import type { PromiseFn, UnboundedQueue } from './queue.js';
5
5
  /**
6
6
  * Describe a semaphore
7
7
  */
8
- export type Semaphore = Lock<void, [
9
- /**
10
- * Current remaining process allowed
11
- */
8
+ export type Semaphore = [
9
+ ...UnboundedQueue<() => void>,
10
+ callback: PromiseFn<void>,
12
11
  remain: number
13
- ]>;
12
+ ];
14
13
  /**
15
14
  * Create a semaphore that allows n accesses
16
15
  */
package/semaphore.js CHANGED
@@ -1 +1 @@
1
- import{nextTick as resolvedPromise}from"./index.js";import{release as lockRelease}from"./lock.js";export let init=(n)=>{let root=[null];let sem=[root,root,(res)=>{sem[0]=sem[0][0]=[null,res]},n];return sem};export let acquire=(s)=>{s[3]--;return s[3]>=0?resolvedPromise:new Promise(s[2])};export let release=(s)=>{if(s[3]<0)lockRelease(s);s[3]++};export let bind=(f,s)=>async(...a)=>{s[3]--;if(s[3]<0)await new Promise(s[2]);try{return await f(...a)}finally{if(s[3]<0)release(s);s[3]++}};
1
+ export let init=(n)=>{let root=[null];let sem=[root,root,(res)=>{sem[0]=sem[0][0]=[null,res]},n];return sem};export let acquire=async(s)=>{s[3]--;if(s[3]<0)return new Promise(s[2])};export let release=(s)=>{if(s[3]<0)(s[1]=s[1][0])[1]();s[3]++};export let bind=(f,s)=>async(...a)=>{s[3]--;if(s[3]<0)await new Promise(s[2]);try{return await f(...a)}finally{if(s[3]<0)(s[1]=s[1][0])[1]();s[3]++}};
package/stream.d.ts CHANGED
@@ -1,28 +1,14 @@
1
1
  /**
2
2
  * @module Streams
3
3
  */
4
- import type { Node as QueueNode } from './queue.js';
5
- import type { AcquireCallback } from './lock.js';
4
+ import type { PromiseFn, UnboundedQueue } from './queue.js';
6
5
  /**
7
6
  * Describe a stream
8
7
  */
9
8
  export type Stream<T extends {} = {}> = [
10
- /**
11
- * Queue head
12
- */
13
- head: QueueNode<T | ((val?: T) => void)>,
14
- /**
15
- * Queue tail
16
- */
17
- tail: QueueNode<T | ((val?: T) => void)>,
18
- /**
19
- * Whether the queue is containing items
20
- */
21
- queueing: boolean,
22
- /**
23
- * Cached callback
24
- */
25
- callback: AcquireCallback<T>
9
+ ...UnboundedQueue<T | ((val?: T) => void)>,
10
+ callback: PromiseFn<T>,
11
+ queueing: boolean
26
12
  ];
27
13
  /**
28
14
  * Create a stream
package/stream.js CHANGED
@@ -1 +1 @@
1
- export let init=()=>{let queue=[null];let s=[queue,queue,false,(res)=>{s[0]=s[0][0]=[null,res]}];return s};export let write=(s,v)=>{if(!s[2]){if(s[1][0]!==null){(s[1]=s[1][0])[1](v);return}s[2]=true}s[0]=s[0][0]=[null,v]};export let read=(s)=>{if(s[2]){s[1]=s[1][0];if(s[1][0]===null)s[2]=false;return Promise.resolve(s[1][1])}return new Promise(s[3])};export let flush=(s)=>{if(!s[2])while(s[1][0]!==null)(s[1]=s[1][0])[1]()};
1
+ export let init=()=>{let queue=[null];let s=[queue,queue,(res)=>{s[0]=s[0][0]=[null,res]},false];return s};export let write=(s,v)=>{if(!s[3]){if(s[1][0]!==null){(s[1]=s[1][0])[1](v);return}s[3]=true}s[0]=s[0][0]=[null,v]};export let read=async(s)=>{if(s[3]){s[1]=s[1][0];if(s[1][0]===null)s[3]=false;return s[1][1]}return new Promise(s[2])};export let flush=(s)=>{if(!s[3])while(s[1][0]!==null)(s[1]=s[1][0])[1]()};
package/topic.d.ts CHANGED
@@ -1,14 +1,13 @@
1
1
  /**
2
2
  * @module Pubsub
3
3
  */
4
- import type { AcquireCallback } from "./lock.js";
5
- import type { Node as QueueNode } from "./queue.js";
4
+ import type { PromiseFn, QueueNode } from './queue.js';
6
5
  /**
7
6
  * Describe a topic
8
7
  */
9
8
  export type Topic<T extends {} = {}> = [
10
9
  head: QueueNode<T>,
11
- callback: AcquireCallback<void>,
10
+ callback: PromiseFn<void>,
12
11
  resolve: (() => void) | null,
13
12
  pending: Promise<void> | null
14
13
  ];
@@ -41,6 +40,6 @@ export declare const flush: (t: Topic) => void;
41
40
  export declare const subscribe: <T extends {}>(t: Topic<T>) => Subscriber<T>;
42
41
  /**
43
42
  * Wait for messages from the topic
44
- * @param t
43
+ * @param s
45
44
  */
46
45
  export declare const dispatch: <T extends {}>(s: Subscriber<T>) => Promise<T | undefined>;
package/defer.d.ts DELETED
@@ -1,22 +0,0 @@
1
- /**
2
- * @module Deferred values
3
- */
4
- /**
5
- * Describe a defer
6
- */
7
- export type Defer<T = any> = [
8
- wait: Promise<T>,
9
- open: (value: T | PromiseLike<T>) => void
10
- ];
11
- /**
12
- * Create a latch
13
- */
14
- export declare const init: <T>() => Defer<T>;
15
- /**
16
- * Wait until a deferred is resolved
17
- */
18
- export declare const wait: <T>(d: Defer<T>) => Promise<T>;
19
- /**
20
- * Resolve the defer
21
- */
22
- export declare const resolve: (<T extends {}>(d: Defer<T>, p: T | PromiseLike<T>) => void) & ((d: Defer<void>) => void);
package/defer.js DELETED
@@ -1 +0,0 @@
1
- export let init=()=>{let r;return[new Promise((res)=>{r=res}),r]};export let wait=(d)=>d[0];export let resolve=(d,p)=>{d[1](p)};
@@ -1,12 +0,0 @@
1
- /**
2
- * @module Dropping queues
3
- */
4
- import type { Fixed } from './queue.js';
5
- export { fixed as init } from './queue.js';
6
- export { pop } from './sliding-queue.js';
7
- /**
8
- * Push an item to a dropping queue
9
- * @param q - The queue to push to
10
- * @param item
11
- */
12
- export declare const push: <T extends {}>(q: Fixed<T>, item: T) => boolean;
package/dropping-queue.js DELETED
@@ -1 +0,0 @@
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/lock.d.ts DELETED
@@ -1,33 +0,0 @@
1
- /**
2
- * @module Lock utilities
3
- */
4
- import type { Node as QueueNode } from './queue.js';
5
- /**
6
- * Describe a lock
7
- */
8
- export type Lock<T = any> = [
9
- /**
10
- * The head of the Promise resolve queue
11
- */
12
- head: QueueNode<(value?: T) => void>,
13
- /**
14
- * The tail of the Promise resolve queue
15
- */
16
- tail: QueueNode<(value?: T) => void>
17
- ];
18
- /**
19
- * Release an item
20
- * @param lock
21
- * @param value
22
- */
23
- export declare const release: <T>(lock: Lock<T>, value?: T) => void;
24
- /**
25
- * Return true if all items are released
26
- * @param lock
27
- */
28
- export declare const released: (lock: Lock) => boolean;
29
- /**
30
- * Release all items of a lock
31
- * @param lock
32
- */
33
- export declare const flush: (lock: Lock) => void;
package/lock.js DELETED
@@ -1 +0,0 @@
1
- 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/queue.js DELETED
@@ -1 +0,0 @@
1
- export let fixed=(n)=>[new Array(n),n,-1,-1];
@@ -1,16 +0,0 @@
1
- /**
2
- * @module Sliding queues
3
- */
4
- import type { Fixed } from './queue.js';
5
- export { fixed as init } from './queue.js';
6
- /**
7
- * Push an item to a sliding queue
8
- * @param q - The queue to push to
9
- * @param item
10
- */
11
- export declare const push: <T extends {}>(q: Fixed<T>, item: T) => void;
12
- /**
13
- * Pop an item from the queue
14
- * @param q - The queue to pop from
15
- */
16
- export declare const pop: <T extends {}>(q: Fixed<T>) => T | undefined;
package/sliding-queue.js DELETED
@@ -1 +0,0 @@
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}};