ciorent 0.0.12 → 0.0.14

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,48 +1,84 @@
1
- A lightweight, low-overhead concurrency library
2
-
3
- # Examples
4
- ## Channel
5
- 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.
1
+ A lightweight, low-overhead concurrency library.
2
+ # Latch
3
+ Latch is a synchronization primitive that allows one process to wait until another completes an operation before continuing execution.
6
4
 
7
5
  ```ts
8
- import * as channel from 'ciorent/channel';
6
+ import * as latch from 'ciorent/latch';
9
7
  import * as cio from 'ciorent';
10
8
 
11
- const c = channel.init<number>();
9
+ const fetchLatch = latch.init();
12
10
 
13
- const run = async () => {
14
- for (let i = 0; i < 10; i++) {
15
- await cio.sleep(10);
16
- channel.send(c, i);
17
- console.log('Sent', i);
18
- }
11
+ const task = async () => {
12
+ // Blocks until the latch is open
13
+ await latch.pause(fetchLatch);
19
14
 
20
- // Send the closed signal to the reciever
21
- // Or else channel.recieve will block forever
22
- channel.close(c);
23
- };
15
+ const res = await fetch('http://example.com');
16
+ console.log('Fetch status:', res.status);
17
+ }
24
18
 
25
- const log = async () => {
26
- while (true) {
27
- // Non-blocking
28
- const x = await channel.recieve(c);
19
+ const prepare = () => {
20
+ console.log('Run before fetch:', performance.now().toFixed(2));
21
+ }
29
22
 
30
- // 'recieve' returns undefined if
31
- // The channel has been closed
32
- if (x == null) break;
23
+ const main = async () => {
24
+ const p = task();
25
+ await cio.sleep(500);
26
+ prepare();
33
27
 
34
- console.log('Recieved', x);
35
- };
28
+ // Allows all previously blocked tasks to run
29
+ latch.open(fetchLatch);
30
+
31
+ // Reclose the latch
32
+ // Tasks that aren't blocked yet will be blocked
33
+ latch.reset(fetchLatch);
34
+
35
+ return p;
36
36
  }
37
37
 
38
- run();
39
- log();
38
+ // Run fetch after 500ms
39
+ await main();
40
40
 
41
- // This runs first
42
- console.log('Starting...');
41
+ // Run fetch after another 500ms
42
+ await main();
43
43
  ```
44
44
 
45
- ## Semaphore
45
+ # Pubsub
46
+ A fast, simple publish-subscribe API.
47
+
48
+ ```ts
49
+ import * as topic from 'ciorent/topic';
50
+ import * as cio from 'ciorent';
51
+
52
+ const messages = topic.init<number>();
53
+
54
+ // A task that publish messages
55
+ const publisher = async () => {
56
+ for (let i = 0; i < 5; i++) {
57
+ await cio.sleep(50);
58
+ topic.pub(messages, i);
59
+ }
60
+
61
+ // Resolve all waiting promises
62
+ // And clear the value queue
63
+ topic.flush(messages);
64
+ }
65
+
66
+ // Spawn 5 tasks that recieve messages
67
+ cio.concurrent(5, async (id: number) => {
68
+ const sub = topic.sub(messages);
69
+
70
+ while (true) {
71
+ // Block until
72
+ const x = await topic.next(sub);
73
+ if (x == null) break;
74
+ console.log(`Task ${id}: ${x}`);
75
+ }
76
+ });
77
+
78
+ publisher();
79
+ ```
80
+
81
+ # Semaphore
46
82
  Semaphore is a concurrency primitive used to control access to a common resource by multiple processes.
47
83
 
48
84
  ```ts
@@ -66,51 +102,49 @@ const task = semaphore.task(
66
102
  cio.concurrent(6, task, 4);
67
103
  ```
68
104
 
69
- ## Latch
70
- Latch is a synchronization primitive that allows one process to wait until another completes an operation before continuing execution.
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.
71
107
 
72
108
  ```ts
73
- import * as latch from 'ciorent/latch';
109
+ import * as channel from 'ciorent/channel';
74
110
  import * as cio from 'ciorent';
75
111
 
76
- const fetchLatch = latch.init();
77
-
78
- const task = async () => {
79
- // Blocks until the latch is open
80
- await latch.pause(fetchLatch);
81
-
82
- const res = await fetch('http://example.com');
83
- console.log('Fetch status:', res.status);
84
- }
112
+ const c = channel.init<number>();
85
113
 
86
- const prepare = () => {
87
- console.log('Run before fetch:', performance.now().toFixed(2));
88
- }
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
+ }
89
120
 
90
- const main = async () => {
91
- const p = task();
92
- await cio.sleep(500);
93
- prepare();
121
+ // Send the closed signal to the reciever
122
+ // Or else channel.recieve will block forever
123
+ channel.close(c);
124
+ };
94
125
 
95
- // Allows all previously blocked tasks to run
96
- latch.open(fetchLatch);
126
+ const log = async () => {
127
+ while (true) {
128
+ // Non-blocking
129
+ const x = await channel.recieve(c);
97
130
 
98
- // Reclose the latch
99
- // Tasks that aren't blocked yet will be blocked
100
- latch.reset(fetchLatch);
131
+ // 'recieve' returns undefined if
132
+ // The channel has been closed
133
+ if (x == null) break;
101
134
 
102
- return p;
135
+ console.log('Recieved', x);
136
+ };
103
137
  }
104
138
 
105
- // Run fetch after 500ms
106
- await main();
139
+ run();
140
+ log();
107
141
 
108
- // Run fetch after another 500ms
109
- await main();
142
+ // This runs first
143
+ console.log('Starting...');
110
144
  ```
111
145
 
112
- ## Utilities
113
- ### Pausing
146
+ # Utilities
147
+ ## Pausing
114
148
  Delay the execution of a function for other asynchronous tasks to run.
115
149
  ```ts
116
150
  import * as cio from 'ciorent';
@@ -140,7 +174,7 @@ task1();
140
174
  task2();
141
175
  ```
142
176
 
143
- ### Sleep
177
+ ## Sleep
144
178
  A cross-runtime sleep function.
145
179
  ```ts
146
180
  import { sleep } from 'ciorent';
@@ -149,7 +183,7 @@ await sleep(500);
149
183
  console.log('Hi');
150
184
  ```
151
185
 
152
- ### Concurrency
186
+ ## Basic concurrency
153
187
  Control how many tasks can be executed concurrently.
154
188
  ```ts
155
189
  import concurrent from 'ciorent/concurrent';
@@ -165,7 +199,7 @@ for (let id = 1; id <= 6; id++)
165
199
  });
166
200
  ```
167
201
 
168
- ### Spawning tasks
202
+ ## Spawning tasks
169
203
  Creating new tasks with controlled concurrency.
170
204
  ```ts
171
205
  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.12",
3
+ "version": "0.0.14",
4
4
  "description": "A lightweight, low-overhead concurrency library",
5
5
  "homepage": "https://ciorent.netlify.app",
6
6
  "repository": {
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 and clear all pending values
45
+ * @param t
46
+ */
47
+ export declare const flush: <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 flush=(t)=>{let head=t[0]=[null,null];for(let i=0,res=t[1],subs=t[2];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)})};