ciorent 0.0.2 → 0.0.4

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,6 @@
1
- # Ciorent
2
- A concurrency library.
1
+ A low-overhead, cross-runtime concurrency library.
3
2
 
4
- ## Example usage
3
+ # Usage
5
4
  Pausing to prioritize an asynchronous task:
6
5
  ```ts
7
6
  import * as cio from 'ciorent';
@@ -10,7 +9,7 @@ import * as cio from 'ciorent';
10
9
  const task1 = async () => {
11
10
  let x = 0;
12
11
  for (let i = 0; i < (Math.random() + 15) * 1e7; i++) {
13
- // Frequent pausing
12
+ // Occasional pausing
14
13
  if (i % 2e6 === 0)
15
14
  await cio.pause;
16
15
 
@@ -31,6 +30,14 @@ task1();
31
30
  task2();
32
31
  ```
33
32
 
33
+ Sleep for a duration:
34
+ ```ts
35
+ import * as cio from 'ciorent';
36
+
37
+ await cio.sleep(1000);
38
+ console.log('Slept for about 1s');
39
+ ```
40
+
34
41
  Go-like channels for synchronizations:
35
42
  ```ts
36
43
  import * as channel from 'ciorent/channel';
@@ -51,12 +58,15 @@ const run = async () => {
51
58
  };
52
59
 
53
60
  const log = async () => {
54
- do {
61
+ while (true) {
55
62
  // Non-blocking
56
63
  const x = await channel.recieve(c);
57
- if (x === channel.closed) break;
64
+
65
+ // If the channel has been closed
66
+ if (x === null) break;
67
+
58
68
  console.log('Recieved', x);
59
- } while (true);
69
+ };
60
70
  }
61
71
 
62
72
  run();
@@ -65,3 +75,79 @@ log();
65
75
  // This runs first
66
76
  console.log('Starting...');
67
77
  ```
78
+
79
+ ## Latch
80
+ Latch is a synchronization tool that works like a gate, pausing tasks until the latch is opened.
81
+
82
+ ```ts
83
+ import * as latch from 'ciorent/latch';
84
+ import * as cio from 'ciorent';
85
+
86
+ const fetchLatch = latch.init();
87
+
88
+ const task = async () => {
89
+ // Blocks until the latch is open
90
+ await latch.pause(fetchLatch);
91
+
92
+ const res = await fetch('http://example.com');
93
+ console.log('Fetch status:', res.status);
94
+ }
95
+
96
+ const prepare = () => {
97
+ console.log('Run before fetch:', performance.now().toFixed(2));
98
+
99
+ // Unblock the latch
100
+ latch.open(fetchLatch);
101
+ }
102
+
103
+ const main = async () => {
104
+ const p = task();
105
+ await cio.sleep(500);
106
+ prepare();
107
+
108
+ return p;
109
+ }
110
+
111
+ // Run fetch after 500ms
112
+ await main();
113
+
114
+ // Re-close the latch
115
+ latch.close(fetchLatch);
116
+
117
+ // Run fetch after another 500ms
118
+ await main();
119
+ ```
120
+
121
+ If you don't need to close the latch again:
122
+ ```ts
123
+ import * as latch from 'ciorent/latch';
124
+ import * as cio from 'ciorent';
125
+
126
+ const [pauseFetch, startFetch] = latch.init();
127
+
128
+ const task = async () => {
129
+ // Blocks until the latch is open
130
+ await pauseFetch;
131
+
132
+ const res = await fetch('http://example.com');
133
+ console.log('Fetch status:', res.status);
134
+ }
135
+
136
+ const prepare = () => {
137
+ console.log('Run before fetch:', performance.now().toFixed(2));
138
+
139
+ // Unblock the latch
140
+ startFetch();
141
+ }
142
+
143
+ const main = async () => {
144
+ const p = task();
145
+ await cio.sleep(500);
146
+ prepare();
147
+
148
+ return p;
149
+ }
150
+
151
+ // Run fetch after 500ms
152
+ await main();
153
+ ```
package/channel.d.ts CHANGED
@@ -14,46 +14,47 @@ export interface Channel<T> {
14
14
  /**
15
15
  * The head of the value queue
16
16
  */
17
- 1: QueueNode<Promise<T | typeof closed>>;
17
+ 1: QueueNode<T>;
18
18
  /**
19
19
  * The tail of the value queue
20
20
  */
21
- 2: QueueNode<Promise<T | typeof closed>>;
21
+ 2: QueueNode<T>;
22
22
  /**
23
23
  * The head of the Promise resolve queue
24
24
  */
25
- 3: QueueNode<(value: Promise<T | typeof closed> | T | typeof closed) => void>;
25
+ 3: QueueNode<(value: T | null) => void>;
26
26
  /**
27
27
  * The tail of the Promise resolve queue
28
28
  */
29
- 4: QueueNode<(value: Promise<T | typeof closed> | T | typeof closed) => void>;
29
+ 4: QueueNode<(value: T | null) => void>;
30
30
  }
31
- /**
32
- * A signal that means the channel has closed
33
- */
34
- export declare const closed: unique symbol;
35
31
  /**
36
32
  * Create a channel
37
33
  */
38
- export declare const init: <T>() => Channel<T>;
34
+ export declare const init: <T extends {}>() => Channel<T>;
39
35
  /**
40
36
  * Send a message to a channel
41
37
  * @param c - The channel to send to
42
38
  * @param t - The message to send
43
39
  */
44
- export declare const send: <T>(c: Channel<T>, t: Promise<T> | T) => void;
40
+ export declare const send: <T>(c: Channel<T>, t: T) => void;
41
+ /**
42
+ * Recieve a message from a channel, return null if the channel is closed
43
+ * @param c
44
+ */
45
+ export declare const recieve: <T>(c: Channel<T>) => Promise<T | null>;
45
46
  /**
46
- * Recieve a message from a channel
47
+ * Recieve a message from a channel, return null if no message is currently in queue
47
48
  * @param c
48
49
  */
49
- export declare const recieve: <T>(c: Channel<T>) => Promise<T | typeof closed>;
50
+ export declare const poll: <T>(c: Channel<T>) => T | null;
50
51
  /**
51
52
  * Close a channel
52
53
  * @param c
53
54
  */
54
55
  export declare const close: <T>(c: Channel<T>) => void;
55
56
  /**
56
- * Check whether a channel is still open yet
57
+ * Check whether a channel is still open
57
58
  * @param c
58
59
  */
59
60
  export declare const active: (c: Channel<any>) => boolean;
package/channel.js CHANGED
@@ -1 +1 @@
1
- export let closed=Symbol();let closedPromise=Promise.resolve(closed);export let init=()=>{let qu=[null,null];let resolveQu=[null,null];return[true,qu,qu,resolveQu,resolveQu]};export let send=(c,t)=>{if(c[0]){if(c[4][1]!==null)(c[4]=c[4][1])[0](t);else c[1]=c[1][1]=[t instanceof Promise?t:Promise.resolve(t),null]}};export let recieve=(c)=>c[2][1]!==null?(c[2]=c[2][1])[0]:c[0]?new Promise((res)=>{c[3]=c[3][1]=[res,null]}):closedPromise;export let close=(c)=>{c[0]=false;while(c[4][1]!==null)(c[4]=c[4][1])[0](closed)};export let active=(c)=>c[0];
1
+ let resolvedNull=Promise.resolve(null);export let init=()=>{let qu=[null,null];let resolveQu=[null,null];return[true,qu,qu,resolveQu,resolveQu]};export let send=(c,t)=>{if(c[0]){if(c[4][1]!==null)(c[4]=c[4][1])[0](t);else c[1]=c[1][1]=[t,null]}};export let recieve=(c)=>c[2][1]!==null?Promise.resolve((c[2]=c[2][1])[0]):c[0]?new Promise((res)=>{c[3]=c[3][1]=[res,null]}):resolvedNull;export let poll=(c)=>c[2][1]!==null?(c[2]=c[2][1])[0]:null;export let close=(c)=>{c[0]=false;while(c[4][1]!==null)(c[4]=c[4][1])[0](null)};export let active=(c)=>c[0];
package/index.d.ts CHANGED
@@ -1,8 +1,17 @@
1
1
  /**
2
2
  * @module
3
- * Utilities for concurrency
3
+ * Other utilities
4
4
  */
5
5
  /**
6
- * Pause to run other tasks
6
+ * Continue running the function on next microtask.
7
+ *
8
+ * You can `await` this **occasionally** in an expensive synchronous operation to avoid
9
+ *
10
+ * blocking the main thread and let other asynchronous task to run.
7
11
  */
8
12
  export declare const pause: Promise<void>;
13
+ /**
14
+ * Sleep for a duration
15
+ * @param ms - Sleep duration in milliseconds
16
+ */
17
+ export declare const sleep: (ms: number) => Promise<void>;
package/index.js CHANGED
@@ -1 +1 @@
1
- export let pause=Promise.resolve();
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)}));
package/latch.d.ts ADDED
@@ -0,0 +1,27 @@
1
+ /**
2
+ * @module
3
+ * Latches
4
+ */
5
+ /**
6
+ * Describe a latch
7
+ */
8
+ export interface Latch {
9
+ 0: Promise<void>;
10
+ 1: () => void;
11
+ }
12
+ /**
13
+ * Create a latch
14
+ */
15
+ export declare const init: () => Latch;
16
+ /**
17
+ * Pause until a latch is opened
18
+ */
19
+ export declare const pause: (latch: Latch) => Promise<void>;
20
+ /**
21
+ * Open a latch
22
+ */
23
+ export declare const open: (latch: Latch) => void;
24
+ /**
25
+ * Close a latch
26
+ */
27
+ export declare const close: (latch: Latch) => void;
package/latch.js ADDED
@@ -0,0 +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 close=(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.2",
3
+ "version": "0.0.4",
4
4
  "description": "A concurrency library",
5
5
  "keywords": [],
6
6
  "license": "MIT",
@@ -12,7 +12,8 @@
12
12
  "build:test": "bun task build && bun test",
13
13
  "build:publish": "bun task build && bun task report-size && bun task publish",
14
14
  "lint": "eslint ./src",
15
- "lint:fix": "eslint ./src --fix"
15
+ "lint:fix": "eslint ./src --fix",
16
+ "docs": "typedoc ./src/** --entryPointStrategy Expand --plugin typedoc-material-theme --skipErrorChecking"
16
17
  },
17
18
  "devDependencies": {
18
19
  "@stylistic/eslint-plugin": "latest",
@@ -23,6 +24,8 @@
23
24
  "mitata": "latest",
24
25
  "terser": "^5.39.0",
25
26
  "tsx": "latest",
27
+ "typedoc": "^0.27.9",
28
+ "typedoc-material-theme": "^1.3.0",
26
29
  "typescript": "latest",
27
30
  "typescript-eslint": "latest"
28
31
  }
@@ -0,0 +1,13 @@
1
+ /**
2
+ * @module
3
+ * Dropping queues
4
+ */
5
+ import type { FixedQueue } from '.';
6
+ export { default as init } from '.';
7
+ export { pop } from './sliding';
8
+ /**
9
+ * Push an item to a dropping queue
10
+ * @param q - The queue to push to
11
+ * @param item
12
+ */
13
+ export declare const push: <T extends {}>(q: FixedQueue<T>, item: T) => boolean;
@@ -0,0 +1 @@
1
+ export{default as init}from".";export{pop}from"./sliding";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,31 @@
1
+ /**
2
+ * @module
3
+ * Queue utilities
4
+ */
5
+ /**
6
+ * Describe a fixed-sized queue
7
+ */
8
+ export interface FixedQueue<T extends {}> {
9
+ /**
10
+ * Pre-allocated queue
11
+ */
12
+ readonly 0: (T | undefined | null)[];
13
+ /**
14
+ * Queue capacity
15
+ */
16
+ readonly 1: number;
17
+ /**
18
+ * Head pointer
19
+ */
20
+ 2: number;
21
+ /**
22
+ * Tail pointer
23
+ */
24
+ 3: number;
25
+ }
26
+ /**
27
+ * Create a fixed queue.
28
+ * @param n - The queue size
29
+ */
30
+ declare const _default: <T extends {}>(n: number) => FixedQueue<T>;
31
+ export default _default;
package/queue/index.js ADDED
@@ -0,0 +1 @@
1
+ export default (n)=>[new Array(n),n,-1,-1];
@@ -0,0 +1,17 @@
1
+ /**
2
+ * @module
3
+ * Sliding queues
4
+ */
5
+ import type { FixedQueue } from '.';
6
+ export { default as init } from '.';
7
+ /**
8
+ * Push an item to a sliding queue
9
+ * @param q - The queue to push to
10
+ * @param item
11
+ */
12
+ export declare const push: <T extends {}>(q: FixedQueue<T>, item: T) => void;
13
+ /**
14
+ * Pop an item from the queue
15
+ * @param q - The queue to pull from
16
+ */
17
+ export declare const pop: <T extends {}>(q: FixedQueue<T>) => T | undefined;
@@ -0,0 +1 @@
1
+ export{default as init}from".";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}};