@amritk/nish-x86_64-linux 0.28.0 → 0.29.0

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/std/json-typed.ts CHANGED
@@ -54,6 +54,40 @@
54
54
  * A map is emptied and filled in the input's order, and every map of one
55
55
  * decoding takes at most `maxMapKeys` keys between them.
56
56
  *
57
+ * **Which keys were given.** An optional field's missing key and a key given
58
+ * the field's initializer leave the same value; the `presence` option tells
59
+ * them apart. It names, for a field, a `boolean` field of the same class that
60
+ * each decoding sets to whether the input gave that field's key — true for a
61
+ * key given `null` too:
62
+ *
63
+ * class UserPatch {
64
+ * static readonly json = { optional: ["name", "email"], presence: { name: "hasName", email: "hasEmail" } };
65
+ * name: string = "";
66
+ * email: string | null = null;
67
+ * hasName: boolean = false;
68
+ * hasEmail: boolean = false;
69
+ * }
70
+ *
71
+ * Any field can be recorded, of any kind and optional or not. A presence
72
+ * field is off the wire: no key reads it, encoding leaves it out, and no option
73
+ * renames it, makes it optional or records it. It is set when the object
74
+ * closes, from the flag the decoder already keeps per field to find a
75
+ * duplicate or a missing key, so recording costs one store per recorded field
76
+ * and allocates nothing, and a class that records nothing compiles to the code
77
+ * it did before. Each object sets its own, so a nested class or an array
78
+ * element answers for its own keys. A decoding that fails may set some of
79
+ * them and not others (when the input is not an object, none), so read them
80
+ * only when `jsonDecode` answered `JSON_DECODE_OK`.
81
+ *
82
+ * **A merge patch (RFC 7396)** is that option's use: a patch class whose
83
+ * every field is optional and recorded, decoded and then applied a field at a
84
+ * time — a recorded key replaces its member, `null` on a `| null` field
85
+ * removes it, an object field is applied the same way one level down, and an
86
+ * array is replaced whole. `null` on a field that is not `| null` is
87
+ * `JSON_DECODE_TYPE`, so a patch that removes what the type cannot lose is
88
+ * refused before any of it is applied. `examples/merge-patch.ts` is the
89
+ * recipe in full.
90
+ *
57
91
  * **Errors are sticky codes**, as the tokenizer's and the writer's are. The
58
92
  * first error sets `failed` to a negative code — a `JSON_DECODE_*` code here,
59
93
  * or the tokenizer's own `JSON_TOK_ERR_*` code when the text is not JSON or
package/std/json.ts CHANGED
@@ -1791,16 +1791,45 @@ const jsonWriterPutDigits64 = (w: JsonWriter, v: i64): boolean => {
1791
1791
  }
1792
1792
 
1793
1793
  /**
1794
- * The digits `${v}` spells for a finite `v`, at the cursor. They are a string
1794
+ * The digits `${v}` spells for a finite `v`, in `buf` from `at`: the new end,
1795
+ * or -1, with nothing written, when `at` is negative or they do not fit —
1796
+ * `jsonWriterPutText`'s rule. Natively the compiler replaces the one call to
1797
+ * it with the runtime's `nish_json_put_f64` (`src/kernels.ts`), which formats
1798
+ * into the stack and copies, so no string is built at all; that is why the
1799
+ * walk takes the array and the cursor rather than the writer.
1800
+ *
1801
+ * As written, which is what Node and `--emit-ts` run, the digits are a string
1795
1802
  * the runtime builds, and nothing holds it once its bytes are copied, so the
1796
1803
  * function's automatic arena scope (LANGUAGE.md, "Memory model", item 2)
1797
1804
  * gives it back before the call returns: a loop of `f64` writes keeps
1798
- * `Arena.used()` flat like every other write, and `tests/link/std_json_writer`
1799
- * measures it. The scope is the compiler's rather than a `using a = arena()`
1800
- * block because this module also runs under Node, which `tests/run.js` holds
1801
- * to `JSON.stringify`, and Node 22 does not parse `using`.
1805
+ * `Arena.used()` flat like every other write either way, and
1806
+ * `tests/link/std_json_writer` measures it. The scope is the compiler's rather
1807
+ * than a `using a = arena()` block because this module also runs under Node,
1808
+ * which `tests/run.js` holds to `JSON.stringify`, and Node 22 does not parse
1809
+ * `using`.
1802
1810
  */
1803
- const jsonWriterPutF64 = (w: JsonWriter, v: f64): boolean => jsonWriterPutText(w, `${v}`)
1811
+ const jsonPutF64Walk = (buf: u8[], at: i32, v: f64): i32 => {
1812
+ const text: string = `${v}`
1813
+ const n: i32 = toI32(text.length)
1814
+ if (at < 0 || at > toI32(buf.length) - n) {
1815
+ return -1
1816
+ }
1817
+ for (let k: i32 = 0; k < n && at + k < toI32(buf.length); k += 1) {
1818
+ buf[at + k] = toU8(text.charCodeAt(k))
1819
+ }
1820
+ return at + n
1821
+ }
1822
+
1823
+ /** The digits `${v}` spells for a finite `v`, at the cursor; all of them or, with `JSON_WRITE_FULL`, none. */
1824
+ const jsonWriterPutF64 = (w: JsonWriter, v: f64): boolean => {
1825
+ const stop: i32 = jsonPutF64Walk(w.buf, w.end, v)
1826
+ if (stop < 0) {
1827
+ w.failed = JSON_WRITE_FULL
1828
+ return false
1829
+ }
1830
+ w.end = stop
1831
+ return true
1832
+ }
1804
1833
 
1805
1834
  /**
1806
1835
  * `s` as `JSON.stringify(s)` writes it — quoted, with the escapes