concurrent-c-node 0.17.2__tar.gz → 0.17.4__tar.gz

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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: concurrent-c-node
3
- Version: 0.17.2
3
+ Version: 0.17.4
4
4
  Summary: JavaScript and npm packages from Python over the Concurrent-C bridge: one spawned Node child per domain, host-controlled lifetime.
5
5
  License: MIT
6
6
  Project-URL: Repository, https://github.com/sreekotay/concurrent-c
@@ -282,8 +282,13 @@ class Bridge:
282
282
  self._ncb += 1
283
283
  self._cbs[fid] = a
284
284
  return {"$f": fid}
285
- if a is None or isinstance(a, (bool, int, str)):
285
+ if a is None or isinstance(a, bool) or isinstance(a, str):
286
286
  return a
287
+ if isinstance(a, int):
288
+ # Exact across JSON: beyond 2^53 tags as {$bi: digits}.
289
+ if -(2 ** 53) < a < 2 ** 53:
290
+ return a
291
+ return {"$bi": str(a)}
287
292
  if isinstance(a, float):
288
293
  if math.isnan(a):
289
294
  return {"$nf": "nan"}
@@ -359,6 +364,22 @@ class Bridge:
359
364
  a.frombytes(raw)
360
365
  return a
361
366
 
367
+ def _decode_val(self, a):
368
+ """Walk nested wire values (arrays/objects) so {$bi} becomes int."""
369
+ if isinstance(a, dict):
370
+ if "$bi" in a:
371
+ return int(a["$bi"])
372
+ if "$nf" in a:
373
+ return {"nan": math.nan, "inf": math.inf,
374
+ "-inf": -math.inf}.get(a["$nf"], math.nan)
375
+ if "$h" in a or "$f" in a or "$ta" in a or "$shm" in a:
376
+ # Top-level shapes only — nested live handles stay opaque.
377
+ return a
378
+ return {k: self._decode_val(v) for k, v in a.items()}
379
+ if isinstance(a, list):
380
+ return [self._decode_val(x) for x in a]
381
+ return a
382
+
362
383
  def _decode_result(self, msg):
363
384
  if "u" in msg:
364
385
  return None
@@ -367,9 +388,13 @@ class Bridge:
367
388
  if "nf" in msg:
368
389
  return {"nan": math.nan, "inf": math.inf,
369
390
  "-inf": -math.inf}[msg["nf"]]
391
+ if "bi" in msg:
392
+ return int(msg["bi"])
370
393
  if "ta" in msg or "shm" in msg:
371
394
  return self._decode_buffer(msg)
372
- return msg.get("v")
395
+ if "v" in msg:
396
+ return self._decode_val(msg["v"])
397
+ return None
373
398
 
374
399
  # ---- surface ----
375
400
 
@@ -106,7 +106,7 @@ function isPlain(v, depth) {
106
106
  if (v === null) return true;
107
107
  const t = typeof v;
108
108
  if (t === 'number') return Number.isFinite(v);
109
- if (t === 'string' || t === 'boolean') return true;
109
+ if (t === 'string' || t === 'boolean' || t === 'bigint') return true;
110
110
  if (t !== 'object') return false;
111
111
  const proto = Object.getPrototypeOf(v);
112
112
  if (Array.isArray(v)) return v.every((x) => isPlain(x, depth + 1));
@@ -115,6 +115,24 @@ function isPlain(v, depth) {
115
115
  return false;
116
116
  }
117
117
 
118
+ /* Tag BigInts beyond 2^53 as {$bi: digits} so JSON never lossy-doubles. */
119
+ function encodeVal(v) {
120
+ if (typeof v === 'bigint') {
121
+ if (v >= -(2n ** 53n) && v <= (2n ** 53n)) return Number(v);
122
+ return { $bi: v.toString() };
123
+ }
124
+ if (Array.isArray(v)) return v.map(encodeVal);
125
+ if (v && typeof v === 'object') {
126
+ const proto = Object.getPrototypeOf(v);
127
+ if (proto === Object.prototype || proto === null) {
128
+ const o = {};
129
+ for (const k of Object.keys(v)) o[k] = encodeVal(v[k]);
130
+ return o;
131
+ }
132
+ }
133
+ return v;
134
+ }
135
+
118
136
  /* Typed buffers cross as tagged bytes: small inline as base64, big
119
137
  * through the shared-memory spill (one memcpy per side; the receiver
120
138
  * consumes-and-unlinks; files are 0600, exclusive-create, inside the
@@ -147,6 +165,10 @@ function encodeResult(v) {
147
165
  if (v === undefined) return { u: 1 };
148
166
  if (typeof v === 'number' && !Number.isFinite(v))
149
167
  return { nf: Number.isNaN(v) ? 'nan' : v > 0 ? 'inf' : '-inf' };
168
+ if (typeof v === 'bigint') {
169
+ if (v >= -(2n ** 53n) && v <= (2n ** 53n)) return { v: Number(v) };
170
+ return { bi: v.toString() };
171
+ }
150
172
  if (v !== null && typeof v === 'object') {
151
173
  const kind = TA_KIND.get(v.constructor);
152
174
  if (kind)
@@ -162,7 +184,7 @@ function encodeResult(v) {
162
184
  Object.keys(v).length === 0)
163
185
  return { h: put(v) };
164
186
  }
165
- if (v === null || isPlain(v, 0)) return { v };
187
+ if (v === null || isPlain(v, 0)) return { v: encodeVal(v) };
166
188
  return { h: put(v) };
167
189
  }
168
190
 
@@ -190,6 +212,7 @@ function decodeVal(a) {
190
212
  if (a.$f !== undefined) return makeCallback(a.$f);
191
213
  if (a.$nf !== undefined)
192
214
  return a.$nf === 'nan' ? NaN : a.$nf === 'inf' ? Infinity : -Infinity;
215
+ if (a.$bi !== undefined) return BigInt(a.$bi);
193
216
  if (a.$ta !== undefined || a.$shm !== undefined) {
194
217
  let buf;
195
218
  if (a.$shm !== undefined) {
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: concurrent-c-node
3
- Version: 0.17.2
3
+ Version: 0.17.4
4
4
  Summary: JavaScript and npm packages from Python over the Concurrent-C bridge: one spawned Node child per domain, host-controlled lifetime.
5
5
  License: MIT
6
6
  Project-URL: Repository, https://github.com/sreekotay/concurrent-c
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "concurrent-c-node"
7
- version = "0.17.2"
7
+ version = "0.17.4"
8
8
  description = "JavaScript and npm packages from Python over the Concurrent-C bridge: one spawned Node child per domain, host-controlled lifetime."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.8"