@pistonite/pure 0.26.2 → 0.26.3

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pistonite/pure",
3
- "version": "0.26.2",
3
+ "version": "0.26.3",
4
4
  "type": "module",
5
5
  "description": "Pure TypeScript libraries for my projects",
6
6
  "homepage": "https://github.com/Pistonite/pure",
@@ -31,6 +31,6 @@
31
31
  },
32
32
  "devDependencies": {
33
33
  "vitest": "^3.1.1",
34
- "mono-dev": "0.1.1"
34
+ "mono-dev": "0.1.2"
35
35
  }
36
36
  }
@@ -0,0 +1,179 @@
1
+ /**
2
+ * A holder for an externally ref-counted object, where free and addref
3
+ * operations are asynchronous.
4
+ *
5
+ * See {@link makeErcType} for how to use
6
+ */
7
+ export type AsyncErc<TName, TRepr = number> = {
8
+ readonly type: TName;
9
+
10
+ /**
11
+ * Underlying object representation.
12
+ *
13
+ * The repr should not be undefinable. undefined means nullptr
14
+ */
15
+ readonly value: TRepr | undefined;
16
+
17
+ /**
18
+ * Free the underlying object.
19
+ *
20
+ * All weak references will be immediately invalidated, and this Erc becomes
21
+ * empty. Awaiting on the promise will ensure that the object is freed externally
22
+ */
23
+ free: () => Promise<void>;
24
+
25
+ /**
26
+ * Assign a new value to this Erc.
27
+ *
28
+ * The old value will be freed, and all weak references will be invalidated.
29
+ */
30
+ assign: (value: TRepr | undefined) => Promise<void>;
31
+
32
+ /**
33
+ * Take the inner value without freeing it.
34
+ *
35
+ * All weak references will be invalidated, and this Erc will become
36
+ * empty
37
+ */
38
+ take: () => TRepr | undefined;
39
+
40
+ /**
41
+ * Create a weak reference to the inner value.
42
+ *
43
+ * When this Erc is freed, all weak references will be invalidated.
44
+ */
45
+ getWeak: () => AsyncErcRef<TName, TRepr>;
46
+
47
+ /**
48
+ * Create a strong reference to the inner value, essentially
49
+ * incrementing the ref count.
50
+ */
51
+ getStrong: () => Promise<AsyncErc<TName, TRepr>>;
52
+ };
53
+
54
+ /**
55
+ * Weak reference to an externally ref-counted object.
56
+ *
57
+ * See {@link makeErcType} for how to use
58
+ */
59
+ export type AsyncErcRef<TName, TRepr = number> = {
60
+ readonly type: TName;
61
+
62
+ /**
63
+ * The underlying object representation.
64
+ *
65
+ * This may become undefined across async calls if the weak reference
66
+ * is invalidated
67
+ */
68
+ readonly value: TRepr | undefined;
69
+
70
+ /**
71
+ * Create a strong reference to the inner value, essentially
72
+ * incrementing the ref count.
73
+ */
74
+ getStrong: () => Promise<AsyncErc<TName, TRepr>>;
75
+ };
76
+
77
+ export type AsyncErcRefType<T> =
78
+ T extends AsyncErc<infer TName, infer TRepr>
79
+ ? AsyncErcRef<TName, TRepr>
80
+ : never;
81
+
82
+ export type AsyncErcTypeConstructor<TName, TRepr> = {
83
+ /**
84
+ * A marker value for the underlying object type.
85
+ *
86
+ * This is commonly a string literal or a symbol.
87
+ */
88
+ marker: TName;
89
+
90
+ /**
91
+ * The function to free the underlying object.
92
+ */
93
+ free: (value: TRepr) => Promise<void> | void;
94
+
95
+ /**
96
+ * Given a value, increase the ref count and return the new reference.
97
+ * The returned representation should be a different value if double indirection
98
+ * is used (each value is a pointer to the smart pointer), or the same value
99
+ * if single indirection is used (the value is pointing to the object itself).
100
+ */
101
+ addRef: (value: TRepr) => Promise<TRepr> | TRepr;
102
+ };
103
+
104
+ /** See {@link makeErcType} */
105
+ export const makeAsyncErcType = <TName, TRepr>({
106
+ marker,
107
+ free,
108
+ addRef,
109
+ }: AsyncErcTypeConstructor<TName, TRepr>): ((
110
+ value: TRepr | undefined,
111
+ ) => AsyncErc<TName, TRepr>) => {
112
+ const createStrongRef = (
113
+ value: TRepr | undefined,
114
+ ): AsyncErc<TName, TRepr> => {
115
+ let weakRef:
116
+ | (AsyncErcRef<TName, TRepr> & { invalidate: () => void })
117
+ | undefined = undefined;
118
+ const invalidateWeakRef = () => {
119
+ if (!weakRef) {
120
+ return;
121
+ }
122
+ const oldWeakRef = weakRef;
123
+ weakRef = undefined;
124
+ oldWeakRef.invalidate();
125
+ };
126
+ const createWeakRef = (initialValue: TRepr | undefined) => {
127
+ const weak = {
128
+ type: marker,
129
+ value: initialValue,
130
+ invalidate: () => {
131
+ weak.value = undefined;
132
+ },
133
+ getStrong: async () => {
134
+ if (weak.value === undefined) {
135
+ return createStrongRef(undefined);
136
+ }
137
+ return createStrongRef(await addRef(weak.value));
138
+ },
139
+ };
140
+ return weak;
141
+ };
142
+ const erc = {
143
+ type: marker,
144
+ value,
145
+ free: async () => {
146
+ if (erc.value !== undefined) {
147
+ invalidateWeakRef();
148
+ const freePromise = free(erc.value);
149
+ erc.value = undefined;
150
+ await freePromise;
151
+ }
152
+ },
153
+ assign: async (newValue: TRepr | undefined) => {
154
+ await erc.free();
155
+ erc.value = newValue;
156
+ },
157
+ take: () => {
158
+ invalidateWeakRef();
159
+ const oldValue = erc.value;
160
+ erc.value = undefined;
161
+ return oldValue;
162
+ },
163
+ getWeak: () => {
164
+ if (!weakRef) {
165
+ weakRef = createWeakRef(erc.value);
166
+ }
167
+ return weakRef;
168
+ },
169
+ getStrong: async () => {
170
+ if (erc.value === undefined) {
171
+ return createStrongRef(undefined);
172
+ }
173
+ return createStrongRef(await addRef(erc.value));
174
+ },
175
+ };
176
+ return erc;
177
+ };
178
+ return createStrongRef;
179
+ };
@@ -7,3 +7,4 @@
7
7
  export { cell, type CellConstructor, type Cell } from "./cell.ts";
8
8
  export { persist, type PersistConstructor, type Persist } from "./persist.ts";
9
9
  export * from "./erc.ts";
10
+ export * from "./asyncerc.ts";