ciorent 0.0.11 → 0.0.13

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,7 +1,5 @@
1
- A lightweight, low-overhead concurrency library
2
-
3
- # Examples
4
- ## Semaphore
1
+ A lightweight, low-overhead concurrency library.
2
+ # Semaphore
5
3
  Semaphore is a concurrency primitive used to control access to a common resource by multiple processes.
6
4
 
7
5
  ```ts
@@ -25,18 +23,61 @@ const task = semaphore.task(
25
23
  cio.concurrent(6, task, 4);
26
24
  ```
27
25
 
28
- ## Channel
26
+ # Latch
27
+ Latch is a synchronization primitive that allows one process to wait until another completes an operation before continuing execution.
28
+
29
+ ```ts
30
+ import * as latch from 'ciorent/latch';
31
+ import * as cio from 'ciorent';
32
+
33
+ const fetchLatch = latch.init();
34
+
35
+ const task = async () => {
36
+ // Blocks until the latch is open
37
+ await latch.pause(fetchLatch);
38
+
39
+ const res = await fetch('http://example.com');
40
+ console.log('Fetch status:', res.status);
41
+ }
42
+
43
+ const prepare = () => {
44
+ console.log('Run before fetch:', performance.now().toFixed(2));
45
+ }
46
+
47
+ const main = async () => {
48
+ const p = task();
49
+ await cio.sleep(500);
50
+ prepare();
51
+
52
+ // Allows all previously blocked tasks to run
53
+ latch.open(fetchLatch);
54
+
55
+ // Reclose the latch
56
+ // Tasks that aren't blocked yet will be blocked
57
+ latch.reset(fetchLatch);
58
+
59
+ return p;
60
+ }
61
+
62
+ // Run fetch after 500ms
63
+ await main();
64
+
65
+ // Run fetch after another 500ms
66
+ await main();
67
+ ```
68
+
69
+ # Channel
29
70
  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.
30
71
 
31
72
  ```ts
32
73
  import * as channel from 'ciorent/channel';
74
+ import * as cio from 'ciorent';
33
75
 
34
76
  const c = channel.init<number>();
35
- const sleep = (ms: number) => new Promise((res) => setTimeout(res, ms));
36
77
 
37
78
  const run = async () => {
38
79
  for (let i = 0; i < 10; i++) {
39
- await sleep(10);
80
+ await cio.sleep(10);
40
81
  channel.send(c, i);
41
82
  console.log('Sent', i);
42
83
  }
@@ -66,51 +107,39 @@ log();
66
107
  console.log('Starting...');
67
108
  ```
68
109
 
69
- ## Latch
70
- Latch is a synchronization primitive that allows one process to wait until another completes an operation before continuing execution.
110
+ # Pubsub
111
+ A simple publish-subscribe API
71
112
 
72
113
  ```ts
73
- import * as latch from 'ciorent/latch';
114
+ import * as topic from 'ciorent/topic';
74
115
  import * as cio from 'ciorent';
75
116
 
76
- const fetchLatch = latch.init();
77
-
78
- const task = async () => {
79
- // Blocks until the latch is open
80
- await latch.pause(fetchLatch);
117
+ const messages = topic.init<number>();
81
118
 
82
- const res = await fetch('http://example.com');
83
- console.log('Fetch status:', res.status);
119
+ // A task that publish messages
120
+ const publisher = async () => {
121
+ for (let i = 0; i < 5; i++) {
122
+ await cio.sleep(50);
123
+ topic.pub(messages, i);
124
+ }
84
125
  }
85
126
 
86
- const prepare = () => {
87
- console.log('Run before fetch:', performance.now().toFixed(2));
88
- }
127
+ // Spawn 5 tasks that recieve messages
128
+ cio.concurrent(5, async (id: number) => {
129
+ const sub = topic.sub(messages);
89
130
 
90
- const main = async () => {
91
- const p = task();
92
- await cio.sleep(500);
93
- prepare();
94
-
95
- // Allows all previously blocked tasks to run
96
- latch.open(fetchLatch);
97
-
98
- // Reclose the latch
99
- // Tasks that aren't blocked yet will be blocked
100
- latch.reset(fetchLatch);
101
-
102
- return p;
103
- }
104
-
105
- // Run fetch after 500ms
106
- await main();
131
+ while (true) {
132
+ const x = await topic.next(sub);
133
+ if (x == null) break;
134
+ console.log(`Task ${id}: ${x}`);
135
+ }
136
+ });
107
137
 
108
- // Run fetch after another 500ms
109
- await main();
138
+ publisher();
110
139
  ```
111
140
 
112
- ## Utilities
113
- ### Pausing
141
+ # Utilities
142
+ ## Pausing
114
143
  Delay the execution of a function for other asynchronous tasks to run.
115
144
  ```ts
116
145
  import * as cio from 'ciorent';
@@ -140,7 +169,7 @@ task1();
140
169
  task2();
141
170
  ```
142
171
 
143
- ### Sleep
172
+ ## Sleep
144
173
  A cross-runtime sleep function.
145
174
  ```ts
146
175
  import { sleep } from 'ciorent';
@@ -149,7 +178,7 @@ await sleep(500);
149
178
  console.log('Hi');
150
179
  ```
151
180
 
152
- ### Concurrency
181
+ ## Basic concurrency
153
182
  Control how many tasks can be executed concurrently.
154
183
  ```ts
155
184
  import concurrent from 'ciorent/concurrent';
@@ -165,7 +194,7 @@ for (let id = 1; id <= 6; id++)
165
194
  });
166
195
  ```
167
196
 
168
- ### Spawning tasks
197
+ ## Spawning tasks
169
198
  Creating new tasks with controlled concurrency.
170
199
  ```ts
171
200
  import * as cio from 'ciorent';
@@ -2,7 +2,7 @@
2
2
  * @module Dropping queues
3
3
  */
4
4
  import type { FixedQueue } from './fixed-queue';
5
- export { default as init } from './fixed-queue';
5
+ export { init } from './fixed-queue';
6
6
  export { pop } from './sliding-queue';
7
7
  /**
8
8
  * Push an item to a dropping queue
package/dropping-queue.js CHANGED
@@ -1 +1 @@
1
- export{default as 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";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};
package/fixed-queue.d.ts CHANGED
@@ -34,5 +34,4 @@ export type QueueNode<T> = [
34
34
  * Create a fixed queue.
35
35
  * @param n - The queue size
36
36
  */
37
- declare const _default: <T extends {}>(n: number) => FixedQueue<T>;
38
- export default _default;
37
+ export declare const init: <T extends {}>(n: number) => FixedQueue<T>;
package/fixed-queue.js CHANGED
@@ -1 +1 @@
1
- export default (n)=>[new Array(n),n,-1,-1];
1
+ export let init=(n)=>[new Array(n),n,-1,-1];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ciorent",
3
- "version": "0.0.11",
3
+ "version": "0.0.13",
4
4
  "description": "A lightweight, low-overhead concurrency library",
5
5
  "homepage": "https://ciorent.netlify.app",
6
6
  "repository": {
@@ -19,7 +19,7 @@
19
19
  "types": "./index.d.ts",
20
20
  "scripts": {
21
21
  "task": "bun scripts/task.ts",
22
- "build:test": "bun docs && bun task build && bun test",
22
+ "build:test": "bun task build && bun docs && bun test",
23
23
  "build:publish": "bun build:test && bun task report-size && bun task publish",
24
24
  "lint": "eslint ./src",
25
25
  "lint:fix": "eslint ./src --fix",
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 task=(s,f)=>async(...a)=>{try{await pause(s);return await f(...a)}finally{signal(s)}};
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 task=(s,f)=>async(...a)=>{await pause(s);try{return await f(...a)}finally{signal(s)}};
@@ -2,7 +2,7 @@
2
2
  * @module Sliding queues
3
3
  */
4
4
  import type { FixedQueue } from './fixed-queue';
5
- export { default as init } from './fixed-queue';
5
+ export { init } from './fixed-queue';
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{default as 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";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 ADDED
@@ -0,0 +1,61 @@
1
+ /**
2
+ * @module Pubsub
3
+ */
4
+ import type { QueueNode } from './fixed-queue';
5
+ /**
6
+ * Describe a topic
7
+ */
8
+ export interface Topic<T extends {}> {
9
+ /**
10
+ * The head node of the value queue
11
+ */
12
+ 0: QueueNode<T>;
13
+ /**
14
+ * The waiting subscriber resolves
15
+ */
16
+ 1: ((res?: T) => void)[];
17
+ /**
18
+ * The waiting subscribers
19
+ */
20
+ 2: Subscriber<T>[];
21
+ }
22
+ /**
23
+ * Create a topic
24
+ */
25
+ export declare const init: <T extends {}>() => Topic<T>;
26
+ /**
27
+ * Describe a topic
28
+ */
29
+ export interface Subscriber<T extends {}> {
30
+ 0: Topic<T>;
31
+ 1: QueueNode<T>;
32
+ }
33
+ /**
34
+ * Subscribe to a topic
35
+ * @param t
36
+ */
37
+ export declare const sub: <T extends {}>(t: Topic<T>) => Subscriber<T>;
38
+ /**
39
+ * Subscribe to a topic
40
+ * @param t
41
+ */
42
+ export declare const pub: <T extends {}>(t: Topic<T>, value: T) => void;
43
+ /**
44
+ * Resolve all waiting promises
45
+ * @param t
46
+ */
47
+ export declare const close: <T extends {}>(t: Topic<T>) => void;
48
+ /**
49
+ * Get the next value in the message queue.
50
+ *
51
+ * Returns `undefined` if the message queue is empty
52
+ * @param t
53
+ */
54
+ export declare const poll: <T extends {}>(t: Subscriber<T>) => T | undefined;
55
+ /**
56
+ * Get the next value in the message queue
57
+ *
58
+ * Returns a promise that resolves when the message queue is not empty
59
+ * @param t
60
+ */
61
+ export declare const next: <T extends {}>(t: Subscriber<T>) => Promise<T | undefined>;
package/topic.js ADDED
@@ -0,0 +1 @@
1
+ export let init=()=>[[null,null],[],[]];export let sub=(t)=>[t,t[0]];export let pub=(t,value)=>{let head=t[0]=t[0][1]=[value,null];for(let i=0,res=t[1],subs=t[2];i<res.length;i++){res[i](value);subs[i][1]=head}t[1]=[];t[2]=[]};export let close=(t)=>{for(let i=0,res=t[1],subs=t[2],head=t[0];i<res.length;i++){res[i]();subs[i][1]=head}t[1]=[];t[2]=[]};export let poll=(t)=>t[1][1]!==null?(t[1]=t[1][1])[0]:undefined;export let next=(t)=>{if(t[1][1]!==null)return Promise.resolve((t[1]=t[1][1])[0]);let topic=t[0];topic[2].push(t);return new Promise((res)=>{topic[1].push(res)})};