@smoothbricks/lmao 0.2.2 → 0.2.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.
Files changed (276) hide show
  1. package/dist/allocator.wasm +0 -0
  2. package/dist/index.d.ts +1 -0
  3. package/dist/index.d.ts.map +1 -1
  4. package/dist/index.js +1 -0
  5. package/dist/lib/JsBufferStrategy.d.ts +4 -3
  6. package/dist/lib/JsBufferStrategy.d.ts.map +1 -1
  7. package/dist/lib/JsBufferStrategy.js +18 -11
  8. package/dist/lib/arrow/lease.d.ts +10 -0
  9. package/dist/lib/arrow/lease.d.ts.map +1 -0
  10. package/dist/lib/arrow/lease.js +33 -0
  11. package/dist/lib/arrow/utils.d.ts +3 -4
  12. package/dist/lib/arrow/utils.d.ts.map +1 -1
  13. package/dist/lib/arrow/utils.js +12 -13
  14. package/dist/lib/arrow/vocabularyDictionary.d.ts +21 -0
  15. package/dist/lib/arrow/vocabularyDictionary.d.ts.map +1 -0
  16. package/dist/lib/arrow/vocabularyDictionary.js +95 -0
  17. package/dist/lib/bufferStrategy.d.ts +3 -2
  18. package/dist/lib/bufferStrategy.d.ts.map +1 -1
  19. package/dist/lib/cloudflare/traceRows.d.ts.map +1 -1
  20. package/dist/lib/cloudflare/traceRows.js +3 -2
  21. package/dist/lib/codegen/evaluatorGenerator.d.ts.map +1 -1
  22. package/dist/lib/codegen/evaluatorGenerator.js +12 -11
  23. package/dist/lib/codegen/fixedPositionWriterGenerator.d.ts +44 -82
  24. package/dist/lib/codegen/fixedPositionWriterGenerator.d.ts.map +1 -1
  25. package/dist/lib/codegen/fixedPositionWriterGenerator.js +223 -162
  26. package/dist/lib/codegen/spanLoggerClosureMaterializer.d.ts +63 -0
  27. package/dist/lib/codegen/spanLoggerClosureMaterializer.d.ts.map +1 -0
  28. package/dist/lib/codegen/spanLoggerClosureMaterializer.js +447 -0
  29. package/dist/lib/codegen/spanLoggerGenerator.d.ts +36 -19
  30. package/dist/lib/codegen/spanLoggerGenerator.d.ts.map +1 -1
  31. package/dist/lib/codegen/spanLoggerGenerator.js +164 -158
  32. package/dist/lib/convertToArrow.d.ts +7 -2
  33. package/dist/lib/convertToArrow.d.ts.map +1 -1
  34. package/dist/lib/convertToArrow.js +499 -285
  35. package/dist/lib/defineOpContext.js +1 -1
  36. package/dist/lib/enumMetadata.d.ts +19 -0
  37. package/dist/lib/enumMetadata.d.ts.map +1 -0
  38. package/dist/lib/enumMetadata.js +86 -0
  39. package/dist/lib/flushScheduler.d.ts.map +1 -1
  40. package/dist/lib/flushScheduler.js +13 -4
  41. package/dist/lib/library.d.ts +16 -98
  42. package/dist/lib/library.d.ts.map +1 -1
  43. package/dist/lib/library.js +32 -525
  44. package/dist/lib/logBinding.d.ts +21 -27
  45. package/dist/lib/logBinding.d.ts.map +1 -1
  46. package/dist/lib/op.d.ts +30 -30
  47. package/dist/lib/op.d.ts.map +1 -1
  48. package/dist/lib/op.js +15 -22
  49. package/dist/lib/opContext/createOpGroup.d.ts +1 -1
  50. package/dist/lib/opContext/createOpGroup.d.ts.map +1 -1
  51. package/dist/lib/opContext/createOpGroup.js +22 -29
  52. package/dist/lib/opContext/defineOp.d.ts +4 -4
  53. package/dist/lib/opContext/defineOp.d.ts.map +1 -1
  54. package/dist/lib/opContext/defineOp.js +53 -10
  55. package/dist/lib/opContext/opGroupTypes.d.ts +2 -2
  56. package/dist/lib/opContext/opTypes.d.ts +1 -1
  57. package/dist/lib/opContext/opTypes.d.ts.map +1 -1
  58. package/dist/lib/opContext/spanContextTypes.d.ts +29 -14
  59. package/dist/lib/opContext/spanContextTypes.d.ts.map +1 -1
  60. package/dist/lib/opContext/types.d.ts +4 -4
  61. package/dist/lib/opContext/types.d.ts.map +1 -1
  62. package/dist/lib/physicalLayoutPlan.d.ts +89 -0
  63. package/dist/lib/physicalLayoutPlan.d.ts.map +1 -0
  64. package/dist/lib/physicalLayoutPlan.js +442 -0
  65. package/dist/lib/resolveMessage.d.ts +9 -0
  66. package/dist/lib/resolveMessage.d.ts.map +1 -0
  67. package/dist/lib/resolveMessage.js +63 -0
  68. package/dist/lib/result.d.ts +5 -7
  69. package/dist/lib/result.d.ts.map +1 -1
  70. package/dist/lib/result.js +19 -26
  71. package/dist/lib/runtimeHint.d.ts +35 -0
  72. package/dist/lib/runtimeHint.d.ts.map +1 -0
  73. package/dist/lib/runtimeHint.js +79 -0
  74. package/dist/lib/schema/types.d.ts +1 -1
  75. package/dist/lib/schema/types.d.ts.map +1 -1
  76. package/dist/lib/span-buffer/aot/v1.d.ts +2 -0
  77. package/dist/lib/span-buffer/aot/v1.d.ts.map +1 -0
  78. package/dist/lib/span-buffer/aot/v1.js +24 -0
  79. package/dist/lib/spanBuffer.d.ts +33 -4
  80. package/dist/lib/spanBuffer.d.ts.map +1 -1
  81. package/dist/lib/spanBuffer.js +583 -91
  82. package/dist/lib/spanBufferStats.d.ts +1 -1
  83. package/dist/lib/spanBufferStats.d.ts.map +1 -1
  84. package/dist/lib/spanContext.d.ts +27 -51
  85. package/dist/lib/spanContext.d.ts.map +1 -1
  86. package/dist/lib/spanContext.js +822 -344
  87. package/dist/lib/sqlite/sqlite-common.d.ts.map +1 -1
  88. package/dist/lib/sqlite/sqlite-common.js +20 -21
  89. package/dist/lib/testing/bun-harness.d.ts +8 -3
  90. package/dist/lib/testing/bun-harness.d.ts.map +1 -1
  91. package/dist/lib/testing/bun-harness.js +30 -18
  92. package/dist/lib/testing/extractFacts.d.ts +1 -1
  93. package/dist/lib/testing/extractFacts.d.ts.map +1 -1
  94. package/dist/lib/testing/extractFacts.js +55 -63
  95. package/dist/lib/testing/facts.d.ts +1 -1
  96. package/dist/lib/testing/facts.d.ts.map +1 -1
  97. package/dist/lib/testing/queryable-span.d.ts +1 -1
  98. package/dist/lib/testing/queryable-span.d.ts.map +1 -1
  99. package/dist/lib/testing/queryable-span.js +26 -28
  100. package/dist/lib/testing/span-query.d.ts.map +1 -1
  101. package/dist/lib/testing/span-query.js +19 -22
  102. package/dist/lib/testing/stdio-replay.d.ts.map +1 -1
  103. package/dist/lib/testing/stdio-replay.js +19 -8
  104. package/dist/lib/threadId.d.ts.map +1 -1
  105. package/dist/lib/threadId.js +6 -3
  106. package/dist/lib/traceRoot.d.ts +30 -8
  107. package/dist/lib/traceRoot.d.ts.map +1 -1
  108. package/dist/lib/traceRoot.es.d.ts +17 -15
  109. package/dist/lib/traceRoot.es.d.ts.map +1 -1
  110. package/dist/lib/traceRoot.es.js +68 -34
  111. package/dist/lib/traceRoot.js +11 -0
  112. package/dist/lib/traceRoot.node.d.ts +17 -19
  113. package/dist/lib/traceRoot.node.d.ts.map +1 -1
  114. package/dist/lib/traceRoot.node.js +66 -38
  115. package/dist/lib/traceTopology.d.ts +42 -0
  116. package/dist/lib/traceTopology.d.ts.map +1 -0
  117. package/dist/lib/traceTopology.js +260 -0
  118. package/dist/lib/tracer.d.ts +9 -5
  119. package/dist/lib/tracer.d.ts.map +1 -1
  120. package/dist/lib/tracer.js +65 -71
  121. package/dist/lib/tracers/ArrayQueueTracer.d.ts +1 -1
  122. package/dist/lib/tracers/ArrayQueueTracer.js +1 -1
  123. package/dist/lib/tracers/StdioTracer.d.ts.map +1 -1
  124. package/dist/lib/tracers/StdioTracer.js +15 -13
  125. package/dist/lib/tracers/TestTracer.d.ts +4 -6
  126. package/dist/lib/tracers/TestTracer.d.ts.map +1 -1
  127. package/dist/lib/tracers/TestTracer.js +6 -8
  128. package/dist/lib/types.d.ts +49 -32
  129. package/dist/lib/types.d.ts.map +1 -1
  130. package/dist/lib/vocabularyRegistry.d.ts +25 -0
  131. package/dist/lib/vocabularyRegistry.d.ts.map +1 -0
  132. package/dist/lib/vocabularyRegistry.js +372 -0
  133. package/dist/lib/wasm/WasmBufferStrategy.d.ts +6 -10
  134. package/dist/lib/wasm/WasmBufferStrategy.d.ts.map +1 -1
  135. package/dist/lib/wasm/WasmBufferStrategy.js +44 -37
  136. package/dist/lib/wasm/wasmAllocator.d.ts +27 -22
  137. package/dist/lib/wasm/wasmAllocator.d.ts.map +1 -1
  138. package/dist/lib/wasm/wasmAllocator.js +66 -44
  139. package/dist/lib/wasm/wasmPhysicalLayout.d.ts +67 -0
  140. package/dist/lib/wasm/wasmPhysicalLayout.d.ts.map +1 -0
  141. package/dist/lib/wasm/wasmPhysicalLayout.js +179 -0
  142. package/dist/lib/wasm/wasmSpanBuffer.d.ts +79 -31
  143. package/dist/lib/wasm/wasmSpanBuffer.d.ts.map +1 -1
  144. package/dist/lib/wasm/wasmSpanBuffer.js +442 -272
  145. package/dist/lib/wasm/wasmTraceRoot.d.ts +24 -22
  146. package/dist/lib/wasm/wasmTraceRoot.d.ts.map +1 -1
  147. package/dist/lib/wasm/wasmTraceRoot.js +110 -71
  148. package/dist/vocabulary/register/v1.d.ts +2 -0
  149. package/dist/vocabulary/register/v1.d.ts.map +1 -0
  150. package/dist/vocabulary/register/v1.js +1 -0
  151. package/dist/wasm.d.ts +5 -0
  152. package/dist/wasm.d.ts.map +1 -0
  153. package/dist/wasm.js +4 -0
  154. package/package.json +54 -6
  155. package/src/index.ts +1 -0
  156. package/src/lib/JsBufferStrategy.ts +27 -9
  157. package/src/lib/__tests__/arrow-builder-integration/arrow-conversion.test.ts +335 -37
  158. package/src/lib/__tests__/arrow-builder-integration/binary-arrow-conversion.test.ts +97 -26
  159. package/src/lib/__tests__/arrow-builder-integration/binary-comparison.test.ts +75 -15
  160. package/src/lib/__tests__/arrow-builder-integration/binary-format-compliance.test.ts +30 -6
  161. package/src/lib/__tests__/arrow-builder-integration/buffer-chaining.test.ts +18 -21
  162. package/src/lib/__tests__/arrow-builder-integration/foundation.test.ts +5 -2
  163. package/src/lib/__tests__/arrow-builder-integration/integration.test.ts +25 -7
  164. package/src/lib/__tests__/arrow-builder-integration/lazy-columns.test.ts +3 -2
  165. package/src/lib/__tests__/buffer-overflow.test.ts +24 -18
  166. package/src/lib/__tests__/capability-span-context.test.ts +505 -0
  167. package/src/lib/__tests__/capacity-tuning.test.ts +5 -3
  168. package/src/lib/__tests__/eager-columns.test.ts +345 -0
  169. package/src/lib/__tests__/enum-metadata-aot.test.ts +153 -0
  170. package/src/lib/__tests__/enum-metadata.test.ts +177 -0
  171. package/src/lib/__tests__/fixtures/empty-vocabulary-runtime.fixture.ts +15 -0
  172. package/src/lib/__tests__/flushScheduler.test.ts +5 -1
  173. package/src/lib/__tests__/identity-view.property.test.ts +179 -0
  174. package/src/lib/__tests__/library.test.ts +19 -235
  175. package/src/lib/__tests__/message-buffer-families.test.ts +878 -0
  176. package/src/lib/__tests__/nested-library-tasks.test.ts +14 -15
  177. package/src/lib/__tests__/op-metadata.test.ts +1 -1
  178. package/src/lib/__tests__/op-type-safety.test.ts +5 -16
  179. package/src/lib/__tests__/physical-layout-plan.test.ts +333 -0
  180. package/src/lib/__tests__/remap-descriptor-integration.test.ts +381 -0
  181. package/src/lib/__tests__/root-context-construction.test.ts +414 -0
  182. package/src/lib/__tests__/span-auto-runtime.test.ts +386 -0
  183. package/src/lib/__tests__/span-buffer-segment-stats.test.ts +221 -0
  184. package/src/lib/__tests__/span-lifecycle.test.ts +53 -25
  185. package/src/lib/__tests__/spanbuffer-materializer-parity.test.ts +266 -0
  186. package/src/lib/__tests__/sync-async-trace.test.ts +24 -23
  187. package/src/lib/__tests__/tag-writer-aot.test.ts +214 -0
  188. package/src/lib/__tests__/test-helpers.ts +67 -12
  189. package/src/lib/__tests__/threadId.test.ts +62 -0
  190. package/src/lib/__tests__/timestamp.test.ts +221 -93
  191. package/src/lib/__tests__/traceTopology.property.test.ts +383 -0
  192. package/src/lib/__tests__/type-narrowing.test.ts +63 -0
  193. package/src/lib/__tests__/vocabulary-dense-decoding.test.ts +405 -0
  194. package/src/lib/__tests__/vocabularyRegistry.test.ts +313 -0
  195. package/src/lib/arrow/lease.ts +43 -0
  196. package/src/lib/arrow/utils.ts +10 -14
  197. package/src/lib/arrow/vocabularyDictionary.ts +123 -0
  198. package/src/lib/bufferStrategy.ts +9 -1
  199. package/src/lib/cloudflare/traceRows.ts +3 -2
  200. package/src/lib/codegen/__tests__/evaluatorGenerator.test.ts +21 -141
  201. package/src/lib/codegen/__tests__/fixedPositionWriter-parity.test.ts +273 -0
  202. package/src/lib/codegen/__tests__/fixedPositionWriter-uint64.test.ts +61 -34
  203. package/src/lib/codegen/__tests__/nullBitmap.test.ts +33 -37
  204. package/src/lib/codegen/__tests__/spanLoggerGenerator.test.ts +34 -18
  205. package/src/lib/codegen/__tests__/spanLoggerMaterializerParity.test.ts +503 -0
  206. package/src/lib/codegen/evaluatorGenerator.ts +18 -13
  207. package/src/lib/codegen/fixedPositionWriterGenerator.ts +329 -245
  208. package/src/lib/codegen/spanLoggerClosureMaterializer.ts +598 -0
  209. package/src/lib/codegen/spanLoggerGenerator.ts +241 -177
  210. package/src/lib/convertToArrow.ts +598 -311
  211. package/src/lib/defineOpContext.ts +1 -1
  212. package/src/lib/enumMetadata.ts +121 -0
  213. package/src/lib/flushScheduler.ts +11 -5
  214. package/src/lib/library.ts +37 -595
  215. package/src/lib/logBinding.ts +21 -27
  216. package/src/lib/op.ts +75 -18
  217. package/src/lib/opContext/__tests__/retry.test.ts +27 -21
  218. package/src/lib/opContext/createOpGroup.ts +33 -31
  219. package/src/lib/opContext/defineOp.ts +88 -11
  220. package/src/lib/opContext/opGroupTypes.ts +2 -2
  221. package/src/lib/opContext/opTypes.ts +1 -1
  222. package/src/lib/opContext/spanContextTypes.ts +98 -17
  223. package/src/lib/opContext/types.ts +7 -3
  224. package/src/lib/physicalLayoutPlan.ts +598 -0
  225. package/src/lib/resolveMessage.ts +67 -0
  226. package/src/lib/result.ts +20 -33
  227. package/src/lib/runtimeHint.ts +98 -0
  228. package/src/lib/schema/__tests__/featureFlags.test.ts +2 -1
  229. package/src/lib/schema/builder.ts +1 -1
  230. package/src/lib/schema/types.ts +1 -1
  231. package/src/lib/span-buffer/aot/v1.ts +26 -0
  232. package/src/lib/spanBuffer.ts +658 -92
  233. package/src/lib/spanBufferStats.ts +1 -1
  234. package/src/lib/spanContext.ts +1350 -861
  235. package/src/lib/sqlite/sqlite-common.ts +20 -31
  236. package/src/lib/testing/__tests__/topology-traversal.test.ts +174 -0
  237. package/src/lib/testing/__tests__/vitest-harness.test.ts +2 -1
  238. package/src/lib/testing/bun-harness.ts +94 -43
  239. package/src/lib/testing/extractFacts.ts +64 -78
  240. package/src/lib/testing/facts.ts +1 -1
  241. package/src/lib/testing/queryable-span.ts +23 -30
  242. package/src/lib/testing/span-query.ts +16 -20
  243. package/src/lib/testing/stdio-replay.ts +25 -8
  244. package/src/lib/testing/vitest-harness.ts +1 -1
  245. package/src/lib/threadId.ts +6 -3
  246. package/src/lib/traceRoot.es.ts +77 -42
  247. package/src/lib/traceRoot.node.ts +75 -46
  248. package/src/lib/traceRoot.ts +41 -14
  249. package/src/lib/traceTopology.ts +279 -0
  250. package/src/lib/tracer.ts +109 -98
  251. package/src/lib/tracers/ArrayQueueTracer.ts +1 -1
  252. package/src/lib/tracers/StdioTracer.ts +15 -13
  253. package/src/lib/tracers/TestTracer.ts +6 -8
  254. package/src/lib/tracers/__tests__/ArrayQueueTracer.test.ts +15 -10
  255. package/src/lib/tracers/__tests__/TestTracer.test.ts +23 -13
  256. package/src/lib/types.ts +64 -33
  257. package/src/lib/vocabularyRegistry.ts +439 -0
  258. package/src/lib/wasm/WasmBufferStrategy.ts +56 -48
  259. package/src/lib/wasm/__tests__/WasmBufferStrategy.test.ts +215 -11
  260. package/src/lib/wasm/__tests__/allocatorFreeBlockClamp.test.ts +86 -0
  261. package/src/lib/wasm/__tests__/wasm-identity-view.test.ts +311 -0
  262. package/src/lib/wasm/__tests__/wasm-integration.test.ts +417 -44
  263. package/src/lib/wasm/__tests__/wasm-message-buffer-families.test.ts +588 -0
  264. package/src/lib/wasm/__tests__/wasmAllocator.test.ts +100 -668
  265. package/src/lib/wasm/__tests__/wasmSpanBuffer.test.ts +419 -63
  266. package/src/lib/wasm/__tests__/wasmTraceRoot.test.ts +24 -29
  267. package/src/lib/wasm/__tests__/wasmTracer.test.ts.disabled +2 -2
  268. package/src/lib/wasm/wasmAllocator.ts +131 -96
  269. package/src/lib/wasm/wasmPhysicalLayout.ts +309 -0
  270. package/src/lib/wasm/wasmSpanBuffer.ts +597 -341
  271. package/src/lib/wasm/wasmTraceRoot.ts +140 -78
  272. package/src/vocabulary/register/v1.ts +1 -0
  273. package/src/wasm.ts +19 -0
  274. package/src/lib/__tests__/remapped-buffer-view-integration.test.ts +0 -319
  275. package/src/lib/__tests__/remapped-buffer-view.test.ts +0 -635
  276. package/src/lib/wasm/allocator.zig +0 -948
@@ -0,0 +1,588 @@
1
+ import { beforeEach, describe, expect, it } from 'bun:test';
2
+ import { createHash } from 'node:crypto';
3
+ import fc from 'fast-check';
4
+ import { createTestOpMetadata, createTestTraceRoot, createTestTracerOptions } from '../../__tests__/test-helpers.js';
5
+ import { defineOpContext } from '../../defineOpContext.js';
6
+ import type { OpMetadata } from '../../opContext/opTypes.js';
7
+ import { MAX_PACKED_MESSAGE_DENSE_INDEX, resolveEntryType, resolveMessage } from '../../resolveMessage.js';
8
+ import {
9
+ type MessageLayoutFamily,
10
+ type MessagePhysicalLayout,
11
+ RUNTIME_HINT_ANALYZED_VALID,
12
+ RUNTIME_HINT_LOG,
13
+ RUNTIME_HINT_MESSAGE_LAYOUT_MIXED,
14
+ RUNTIME_HINT_MESSAGE_PHYSICAL_SPECIALIZED,
15
+ RUNTIME_HINT_RESULT,
16
+ } from '../../runtimeHint.js';
17
+ import { S } from '../../schema/builder.js';
18
+ import { defineLogSchema } from '../../schema/defineLogSchema.js';
19
+ import {
20
+ ENTRY_TYPE_DEBUG,
21
+ ENTRY_TYPE_INFO,
22
+ ENTRY_TYPE_SPAN_OK,
23
+ ENTRY_TYPE_SPAN_START,
24
+ } from '../../schema/systemSchema.js';
25
+ import { createOverflowBuffer, createSpanBuffer, EMPTY_SCOPE, getSpanBufferClass } from '../../spanBuffer.js';
26
+ import { createTraceId } from '../../traceId.js';
27
+ import { TestTracer } from '../../tracers/TestTracer.js';
28
+ import type { AnySpanBuffer, SpanBuffer } from '../../types.js';
29
+ import { registerVocabularyFragment, type VocabularyFragment } from '../../vocabularyRegistry.js';
30
+ import { createWasmAllocator, type WasmAllocator } from '../wasmAllocator.js';
31
+ import { createWasmLayoutTemplate, getWasmPhysicalLayout } from '../wasmPhysicalLayout.js';
32
+ import {
33
+ createWasmChildSpanBuffer,
34
+ createWasmOverflowBuffer,
35
+ createWasmSpanBuffer,
36
+ getWasmSpanBufferClass,
37
+ type WasmSpanBufferInstance,
38
+ } from '../wasmSpanBuffer.js';
39
+ import { WasmTraceRoot } from '../wasmTraceRoot.js';
40
+
41
+ const vocabularyEncoder = new TextEncoder();
42
+
43
+ function encodeVocabularyRecord(text: string): Uint8Array {
44
+ const textBytes = vocabularyEncoder.encode(text);
45
+ const record = new Uint8Array(4 + textBytes.length + 2);
46
+ new DataView(record.buffer).setUint32(0, textBytes.length, true);
47
+ record.set(textBytes, 4);
48
+ return record;
49
+ }
50
+
51
+ function vocabularyFragmentHash(fragment: Omit<VocabularyFragment, 'contentHash'>): string {
52
+ const algorithm = vocabularyEncoder.encode(fragment.idAlgorithm);
53
+ const byteLength =
54
+ 1 +
55
+ 2 +
56
+ algorithm.length +
57
+ 4 +
58
+ fragment.ids.length * 4 +
59
+ 4 +
60
+ fragment.kindTags.length +
61
+ 4 +
62
+ fragment.utf8.length +
63
+ 4 +
64
+ fragment.offsets.length * 4;
65
+ const bytes = new Uint8Array(byteLength);
66
+ const view = new DataView(bytes.buffer);
67
+ let offset = 0;
68
+ bytes[offset++] = fragment.schemaVersion;
69
+ view.setUint16(offset, algorithm.length, true);
70
+ offset += 2;
71
+ bytes.set(algorithm, offset);
72
+ offset += algorithm.length;
73
+ view.setUint32(offset, fragment.ids.length, true);
74
+ offset += 4;
75
+ for (const id of fragment.ids) {
76
+ view.setUint32(offset, id, true);
77
+ offset += 4;
78
+ }
79
+ view.setUint32(offset, fragment.kindTags.length, true);
80
+ offset += 4;
81
+ bytes.set(fragment.kindTags, offset);
82
+ offset += fragment.kindTags.length;
83
+ view.setUint32(offset, fragment.utf8.length, true);
84
+ offset += 4;
85
+ bytes.set(fragment.utf8, offset);
86
+ offset += fragment.utf8.length;
87
+ view.setUint32(offset, fragment.offsets.length, true);
88
+ offset += 4;
89
+ for (const boundary of fragment.offsets) {
90
+ view.setInt32(offset, boundary, true);
91
+ offset += 4;
92
+ }
93
+ return createHash('sha256').update(bytes).digest('hex');
94
+ }
95
+
96
+ function makeVocabularyFragment(text: string): VocabularyFragment {
97
+ const record = encodeVocabularyRecord(text);
98
+ const digest = createHash('sha256').update(Uint8Array.of(1)).update(record).digest();
99
+ const fragment: Omit<VocabularyFragment, 'contentHash'> = {
100
+ schemaVersion: 1,
101
+ idAlgorithm: 'sha256-24-v1',
102
+ ids: new Uint32Array([(digest[0] << 16) | (digest[1] << 8) | digest[2]]),
103
+ kindTags: new Uint8Array([1]),
104
+ utf8: record,
105
+ offsets: new Int32Array([0, record.length]),
106
+ };
107
+ return { ...fragment, contentHash: vocabularyFragmentHash(fragment) };
108
+ }
109
+
110
+ const WASM_VOCABULARY_TEXT = 'WASM local vocabulary literal';
111
+ const WASM_VOCABULARY_BINDING = registerVocabularyFragment(makeVocabularyFragment(WASM_VOCABULARY_TEXT));
112
+ const WASM_DENSE_INDEX = WASM_VOCABULARY_BINDING[0];
113
+
114
+ const CAPACITY = 8;
115
+ const context = defineOpContext({ logSchema: defineLogSchema({ marker: S.category(), count: S.number() }) });
116
+ const schema = context.logBinding.logSchema;
117
+ const lifecycleTracer = new TestTracer(context, createTestTracerOptions<typeof schema>());
118
+ const currentMixedOp = context.defineOp('wasm-current-mixed', (ctx) => ctx.ok(null), undefined, {
119
+ runtimeHint:
120
+ RUNTIME_HINT_ANALYZED_VALID | RUNTIME_HINT_LOG | RUNTIME_HINT_RESULT | RUNTIME_HINT_MESSAGE_LAYOUT_MIXED | CAPACITY,
121
+ localMessageDictionary: [WASM_DENSE_INDEX],
122
+ });
123
+ const specializedMixedOp = context.defineOp('wasm-specialized-mixed', (ctx) => ctx.ok(null), undefined, {
124
+ runtimeHint:
125
+ RUNTIME_HINT_ANALYZED_VALID |
126
+ RUNTIME_HINT_LOG |
127
+ RUNTIME_HINT_RESULT |
128
+ RUNTIME_HINT_MESSAGE_LAYOUT_MIXED |
129
+ RUNTIME_HINT_MESSAGE_PHYSICAL_SPECIALIZED |
130
+ CAPACITY,
131
+ });
132
+
133
+ function align(value: number, alignment: number): number {
134
+ return (value + alignment - 1) & ~(alignment - 1);
135
+ }
136
+
137
+ function expectWasmFamilyShape(buffer: WasmSpanBufferInstance<typeof schema>, family: MessageLayoutFamily): void {
138
+ if (buffer._messageLayoutFamily !== family) {
139
+ throw new Error(`Expected ${family} WASM buffer, received ${buffer._messageLayoutFamily}`);
140
+ }
141
+ expect(buffer._layout.messageLayoutFamily).toBe(family);
142
+ expect(buffer._descriptor.layout).toBe(buffer._layout);
143
+ if (family === 'static-only') {
144
+ expect('message_values' in buffer).toBe(false);
145
+ expect(Object.hasOwn(buffer, '_message')).toBe(false);
146
+ expect(Object.hasOwn(buffer, '_spanName')).toBe(true);
147
+ expect(Object.hasOwn(buffer, '_terminalMessage')).toBe(true);
148
+ } else if (family === 'dynamic-only') {
149
+ expect(buffer.message_values).toBeInstanceOf(Array);
150
+ expect(Object.hasOwn(buffer, '_message')).toBe(true);
151
+ expect(Object.hasOwn(buffer, '_spanName')).toBe(true);
152
+ expect(Object.hasOwn(buffer, '_terminalMessage')).toBe(false);
153
+ } else {
154
+ expect(buffer.message_values).toBeInstanceOf(Array);
155
+ expect(Object.hasOwn(buffer, '_message')).toBe(true);
156
+ expect(Object.hasOwn(buffer, '_spanName')).toBe(false);
157
+ expect(Object.hasOwn(buffer, '_terminalMessage')).toBe(false);
158
+ }
159
+ }
160
+
161
+ function expectWasmPhysicalShape(
162
+ buffer: WasmSpanBufferInstance<typeof schema>,
163
+ physicalLayout: MessagePhysicalLayout,
164
+ ): void {
165
+ if (buffer._messagePhysicalLayout !== physicalLayout) {
166
+ throw new Error(`Expected ${physicalLayout} WASM buffer, received ${buffer._messagePhysicalLayout}`);
167
+ }
168
+ expect(buffer._layout.messagePhysicalLayout).toBe(physicalLayout);
169
+ const hasStaticMessages = buffer._messageLayoutFamily !== 'dynamic-only';
170
+ if (physicalLayout === 'packed') {
171
+ expect(buffer._rowHeaders).toBeInstanceOf(Uint32Array);
172
+ expect('entry_type' in buffer).toBe(false);
173
+ expect('_messageIds' in buffer).toBe(false);
174
+ expect('_logHeaders' in buffer).toBe(false);
175
+ expect('message_nulls' in buffer).toBe(false);
176
+ } else {
177
+ expect(buffer.entry_type).toBeInstanceOf(Uint8Array);
178
+ expect('_rowHeaders' in buffer).toBe(false);
179
+ if (physicalLayout === 'current' && hasStaticMessages) {
180
+ expect(buffer._messageIds).toBeInstanceOf(Uint16Array);
181
+ expect('_logHeaders' in buffer).toBe(false);
182
+ } else if (physicalLayout === 'specialized' && hasStaticMessages) {
183
+ expect('_messageIds' in buffer).toBe(false);
184
+ expect(buffer._logHeaders).toBeInstanceOf(Uint32Array);
185
+ } else {
186
+ expect('_messageIds' in buffer).toBe(false);
187
+ expect('_logHeaders' in buffer).toBe(false);
188
+ }
189
+ expect('message_nulls' in buffer).toBe(false);
190
+ }
191
+ }
192
+
193
+ function writeEntryType(buffer: AnySpanBuffer, row: number, entryType: number): void {
194
+ if (buffer._rowHeaders !== undefined) {
195
+ buffer._rowHeaders[row] = ((buffer._rowHeaders[row] & 0xffffff00) | entryType) >>> 0;
196
+ return;
197
+ }
198
+ if (buffer.entry_type === undefined) throw new Error('Expected split entry-type lane');
199
+ {
200
+ const entryTypes = buffer.entry_type;
201
+ if (entryTypes === undefined) throw new Error('Expected split entry-type lane');
202
+ entryTypes[row] = entryType;
203
+ }
204
+ }
205
+
206
+ function writeStaticDense(buffer: AnySpanBuffer, row: number, entryType: number, denseIndex: number): void {
207
+ if (buffer._rowHeaders !== undefined) {
208
+ buffer._rowHeaders[row] = (((denseIndex + 1) << 8) | entryType) >>> 0;
209
+ return;
210
+ }
211
+ if (buffer.entry_type === undefined) throw new Error('Expected nonpacked entry-type lane');
212
+ buffer.entry_type[row] = entryType;
213
+ if (buffer._messagePhysicalLayout === 'current') {
214
+ if (buffer._messageIds === undefined) throw new Error('Expected current local-ID lane');
215
+ const localOrdinal = buffer._opMetadata._physicalLayoutPlan?.localMessageDictionary.indexOf(denseIndex) ?? -1;
216
+ if (localOrdinal < 0) throw new Error(`Dense index ${denseIndex} is absent from the current local dictionary`);
217
+ buffer._messageIds[row] = localOrdinal + 1;
218
+ } else {
219
+ if (buffer._logHeaders === undefined) throw new Error('Expected specialized global dense lane');
220
+ buffer._logHeaders[row] = denseIndex + 1;
221
+ }
222
+ }
223
+
224
+ function collectMessages(root: AnySpanBuffer): Array<string | undefined> {
225
+ const messages: Array<string | undefined> = [];
226
+ let segment: AnySpanBuffer | undefined = root;
227
+ let first = true;
228
+ while (segment) {
229
+ for (let row = first ? 2 : 0; row < segment._writeIndex; row++) messages.push(resolveMessage(segment, row));
230
+ first = false;
231
+ segment = segment._overflow;
232
+ }
233
+ return messages;
234
+ }
235
+
236
+ describe('WASM specialized message buffer families', () => {
237
+ let allocator: WasmAllocator;
238
+ let traceRoot: WasmTraceRoot<typeof schema>;
239
+ const metadata = createTestOpMetadata({ name: 'wasm-message-family' });
240
+
241
+ beforeEach(async () => {
242
+ allocator = await createWasmAllocator({ capacity: 64 });
243
+ allocator.reset();
244
+ allocator.setThreadId(0, 42);
245
+ traceRoot = new WasmTraceRoot<typeof schema>(allocator, createTraceId('wasm-message-family'), lifecycleTracer);
246
+ });
247
+
248
+ function createBuffer(
249
+ family: MessageLayoutFamily,
250
+ physicalLayout: MessagePhysicalLayout = 'current',
251
+ opMetadata: OpMetadata = metadata,
252
+ ): WasmSpanBufferInstance<typeof schema> {
253
+ return createWasmSpanBuffer(
254
+ schema,
255
+ {
256
+ allocator,
257
+ capacity: CAPACITY,
258
+ messageLayoutFamily: family,
259
+ messagePhysicalLayout: physicalLayout,
260
+ },
261
+ traceRoot,
262
+ EMPTY_SCOPE,
263
+ opMetadata,
264
+ opMetadata,
265
+ );
266
+ }
267
+
268
+ it('caches all family/mode classes and exposes exact lane offsets and bytes for arbitrary capacities', () => {
269
+ const families = ['static-only', 'dynamic-only', 'mixed'] as const;
270
+ const modes = ['current', 'specialized', 'packed'] as const;
271
+ const classes = families.flatMap((family) => modes.map((mode) => getWasmSpanBufferClass(schema, family, mode)));
272
+ const templates = families.flatMap((family) => modes.map((mode) => createWasmLayoutTemplate(schema, family, mode)));
273
+ expect(new Set(classes).size).toBe(9);
274
+ expect(new Set(templates).size).toBe(9);
275
+ for (const family of families) {
276
+ for (const mode of modes) {
277
+ expect(getWasmSpanBufferClass(schema, family, mode)).toBe(getWasmSpanBufferClass(schema, family, mode));
278
+ expect(createWasmLayoutTemplate(schema, family, mode)).toBe(createWasmLayoutTemplate(schema, family, mode));
279
+ }
280
+ }
281
+
282
+ fc.assert(
283
+ fc.property(fc.integer({ min: 1, max: 512 }), (capacity) => {
284
+ const timestampBytes = capacity * BigUint64Array.BYTES_PER_ELEMENT;
285
+ const entryTypeBytes = capacity * Uint8Array.BYTES_PER_ELEMENT;
286
+ for (const family of families) {
287
+ for (const mode of modes) {
288
+ const template = createWasmLayoutTemplate(schema, family, mode);
289
+ const layout = getWasmPhysicalLayout(schema, capacity, family, mode);
290
+ const hasStaticMessages = family !== 'dynamic-only';
291
+ expect(layout).toBe(template.forCapacity(capacity));
292
+ expect(layout.messageLayoutFamily).toBe(family);
293
+ expect(layout.messagePhysicalLayout).toBe(mode);
294
+ expect(layout.system.timestampOffset).toBe(0);
295
+ expect(layout.system.messageValueOffset).toBe(family === 'static-only' ? null : 0);
296
+ expect('messageIdValidityOffset' in layout.system).toBe(false);
297
+ expect('messageValidityOffset' in layout.system).toBe(false);
298
+
299
+ if (mode === 'packed') {
300
+ const rowHeaderOffset = align(timestampBytes, Uint32Array.BYTES_PER_ELEMENT);
301
+ expect(layout.system.entryTypeOffset).toBeNull();
302
+ expect(layout.system.messageIdOffset).toBeNull();
303
+ expect(layout.system.messageDenseIndexOffset).toBeNull();
304
+ expect(layout.system.rowHeaderOffset).toBe(rowHeaderOffset);
305
+ expect(layout.system.byteLength).toBe(
306
+ align(rowHeaderOffset + capacity * Uint32Array.BYTES_PER_ELEMENT, BigUint64Array.BYTES_PER_ELEMENT),
307
+ );
308
+ } else {
309
+ const entryTypeOffset = timestampBytes;
310
+ expect(layout.system.entryTypeOffset).toBe(entryTypeOffset);
311
+ expect(layout.system.rowHeaderOffset).toBeNull();
312
+ if (!hasStaticMessages) {
313
+ expect(layout.system.messageIdOffset).toBeNull();
314
+ expect(layout.system.messageDenseIndexOffset).toBeNull();
315
+ expect(layout.system.byteLength).toBe(
316
+ align(entryTypeOffset + entryTypeBytes, BigUint64Array.BYTES_PER_ELEMENT),
317
+ );
318
+ } else if (mode === 'current') {
319
+ const messageIdOffset = align(entryTypeOffset + entryTypeBytes, Uint16Array.BYTES_PER_ELEMENT);
320
+ expect(layout.system.messageIdOffset).toBe(messageIdOffset);
321
+ expect(layout.system.messageDenseIndexOffset).toBeNull();
322
+ expect(layout.system.byteLength).toBe(
323
+ align(messageIdOffset + capacity * Uint16Array.BYTES_PER_ELEMENT, BigUint64Array.BYTES_PER_ELEMENT),
324
+ );
325
+ } else {
326
+ const messageDenseIndexOffset = align(entryTypeOffset + entryTypeBytes, Uint32Array.BYTES_PER_ELEMENT);
327
+ expect(layout.system.messageIdOffset).toBeNull();
328
+ expect(layout.system.messageDenseIndexOffset).toBe(messageDenseIndexOffset);
329
+ expect(layout.system.byteLength).toBe(
330
+ align(
331
+ messageDenseIndexOffset + capacity * Uint32Array.BYTES_PER_ELEMENT,
332
+ BigUint64Array.BYTES_PER_ELEMENT,
333
+ ),
334
+ );
335
+ }
336
+ }
337
+ }
338
+ }
339
+ }),
340
+ { numRuns: 100 },
341
+ );
342
+ });
343
+
344
+ it('distinguishes returned dense bindings, null, and raw rows in current and specialized lanes', () => {
345
+ for (const { mode, op } of [
346
+ { mode: 'current' as const, op: currentMixedOp },
347
+ { mode: 'specialized' as const, op: specializedMixedOp },
348
+ ]) {
349
+ const buffer = createBuffer('mixed', mode, op.metadata);
350
+ expectWasmFamilyShape(buffer, 'mixed');
351
+ expectWasmPhysicalShape(buffer, mode);
352
+ writeStaticDense(buffer, 0, ENTRY_TYPE_INFO, WASM_DENSE_INDEX);
353
+ buffer._writeIndex = 3;
354
+ expect(resolveEntryType(buffer, 0)).toBe(ENTRY_TYPE_INFO);
355
+ expect(resolveMessage(buffer, 0)).toBe(WASM_VOCABULARY_TEXT);
356
+ if (mode === 'current') expect(buffer._messageIds?.[0]).toBe(1);
357
+ else expect(buffer._logHeaders?.[0]).toBe(WASM_DENSE_INDEX + 1);
358
+ expect('message_nulls' in buffer).toBe(false);
359
+
360
+ writeEntryType(buffer, 1, ENTRY_TYPE_DEBUG);
361
+ expect(resolveMessage(buffer, 1)).toBeUndefined();
362
+ buffer.message(1, '');
363
+ expect(resolveMessage(buffer, 1)).toBe('');
364
+ writeEntryType(buffer, 2, ENTRY_TYPE_DEBUG);
365
+ expect(resolveMessage(buffer, 2)).toBeUndefined();
366
+ if (mode === 'specialized') {
367
+ if (buffer._logHeaders === undefined) throw new Error('Expected specialized dense lane');
368
+ buffer._logHeaders[2] = MAX_PACKED_MESSAGE_DENSE_INDEX + 1;
369
+ expect(buffer._logHeaders[2]).toBe(0x00ffffff);
370
+ }
371
+ }
372
+ });
373
+
374
+ it('clears stale raw rows across allocator reuse before current and specialized static/null/raw transitions', () => {
375
+ for (const { mode, metadata } of [
376
+ { mode: 'current' as const, metadata: currentMixedOp.metadata },
377
+ { mode: 'specialized' as const, metadata: specializedMixedOp.metadata },
378
+ ]) {
379
+ allocator.reset();
380
+ allocator.setThreadId(0, 42);
381
+ traceRoot = new WasmTraceRoot<typeof schema>(allocator, createTraceId(`${mode}-raw-cycle`), lifecycleTracer);
382
+ const staleRaw = createBuffer('mixed', mode, metadata);
383
+ writeEntryType(staleRaw, 0, ENTRY_TYPE_DEBUG);
384
+ staleRaw.message(0, 'stale raw');
385
+ expect(resolveMessage(staleRaw, 0)).toBe('stale raw');
386
+ const reusedSystemPtr = staleRaw._descriptor.systemPtr;
387
+ const reducedSystemBytes = staleRaw._layout.system.byteLength;
388
+
389
+ allocator.reset();
390
+ allocator.setThreadId(0, 42);
391
+ traceRoot = new WasmTraceRoot<typeof schema>(allocator, createTraceId(`${mode}-static-cycle`), lifecycleTracer);
392
+ const staticRow = createBuffer('mixed', mode, metadata);
393
+ expect(staticRow._descriptor.systemPtr).toBe(reusedSystemPtr);
394
+ expect(staticRow._layout.system.byteLength).toBe(reducedSystemBytes);
395
+ expect(staticRow.message_values?.[0]).toBeUndefined();
396
+ expect('message_nulls' in staticRow).toBe(false);
397
+ writeStaticDense(staticRow, 0, ENTRY_TYPE_INFO, WASM_DENSE_INDEX);
398
+ expect(resolveMessage(staticRow, 0)).toBe(WASM_VOCABULARY_TEXT);
399
+ if (mode === 'current') expect(staticRow._messageIds?.[0]).toBe(1);
400
+ else expect(staticRow._logHeaders?.[0]).toBe(WASM_DENSE_INDEX + 1);
401
+
402
+ allocator.reset();
403
+ allocator.setThreadId(0, 42);
404
+ traceRoot = new WasmTraceRoot<typeof schema>(allocator, createTraceId(`${mode}-null-cycle`), lifecycleTracer);
405
+ const nullRow = createBuffer('mixed', mode, metadata);
406
+ expect(nullRow._descriptor.systemPtr).toBe(reusedSystemPtr);
407
+ writeEntryType(nullRow, 0, ENTRY_TYPE_DEBUG);
408
+ expect(nullRow.message_values?.[0]).toBeUndefined();
409
+ expect(resolveMessage(nullRow, 0)).toBeUndefined();
410
+ if (mode === 'current') expect(nullRow._messageIds?.[0]).toBe(0);
411
+ else expect(nullRow._logHeaders?.[0]).toBe(0);
412
+
413
+ allocator.reset();
414
+ allocator.setThreadId(0, 42);
415
+ traceRoot = new WasmTraceRoot<typeof schema>(
416
+ allocator,
417
+ createTraceId(`${mode}-fresh-raw-cycle`),
418
+ lifecycleTracer,
419
+ );
420
+ const freshRaw = createBuffer('mixed', mode, metadata);
421
+ expect(freshRaw._descriptor.systemPtr).toBe(reusedSystemPtr);
422
+ writeEntryType(freshRaw, 0, ENTRY_TYPE_DEBUG);
423
+ freshRaw.message(0, '');
424
+ expect(resolveMessage(freshRaw, 0)).toBe('');
425
+ if (mode === 'current') expect(freshRaw._messageIds?.[0]).toBe(0);
426
+ else expect(freshRaw._logHeaders?.[0]).toBe(0);
427
+ }
428
+ });
429
+
430
+ it('allocates packed lanes for all families and preserves dense-zero/max/null/raw semantics', () => {
431
+ for (const family of ['static-only', 'dynamic-only', 'mixed'] as const) {
432
+ const buffer = createBuffer(family, 'packed');
433
+ expectWasmFamilyShape(buffer, family);
434
+ expectWasmPhysicalShape(buffer, 'packed');
435
+ if (buffer._rowHeaders === undefined) throw new Error('Expected packed WASM headers');
436
+ writeStaticDense(buffer, 0, ENTRY_TYPE_SPAN_START, WASM_DENSE_INDEX);
437
+ buffer._writeIndex = 2;
438
+ expect(buffer._rowHeaders[0] >>> 8).toBe(WASM_DENSE_INDEX + 1);
439
+ expect(resolveEntryType(buffer, 0)).toBe(ENTRY_TYPE_SPAN_START);
440
+ expect(resolveMessage(buffer, 0)).toBe(WASM_VOCABULARY_TEXT);
441
+
442
+ buffer._rowHeaders[1] = (((MAX_PACKED_MESSAGE_DENSE_INDEX + 1) << 8) | ENTRY_TYPE_SPAN_OK) >>> 0;
443
+ expect(buffer._rowHeaders[1] >>> 8).toBe(0x00ffffff);
444
+ if (family !== 'static-only') {
445
+ writeEntryType(buffer, 2, ENTRY_TYPE_DEBUG);
446
+ buffer._writeIndex = 3;
447
+ expect(resolveMessage(buffer, 2)).toBeUndefined();
448
+ buffer.message(2, `raw-packed-${family}`);
449
+ expect(buffer._rowHeaders[2] >>> 8).toBe(0);
450
+ expect(resolveMessage(buffer, 2)).toBe(`raw-packed-${family}`);
451
+ }
452
+ }
453
+ });
454
+
455
+ it('propagates family, physical layout, pointers, and omissions through child and overflow descriptors', () => {
456
+ for (const family of ['static-only', 'dynamic-only', 'mixed'] as const) {
457
+ for (const physicalLayout of ['current', 'specialized', 'packed'] as const) {
458
+ const modeMetadata =
459
+ physicalLayout === 'current'
460
+ ? currentMixedOp.metadata
461
+ : physicalLayout === 'specialized'
462
+ ? specializedMixedOp.metadata
463
+ : metadata;
464
+ const root = createBuffer(family, physicalLayout, modeMetadata);
465
+ const child = createWasmChildSpanBuffer(
466
+ root,
467
+ { allocator, capacity: CAPACITY, messageLayoutFamily: family },
468
+ traceRoot,
469
+ EMPTY_SCOPE,
470
+ modeMetadata,
471
+ modeMetadata,
472
+ );
473
+ const overflow = createWasmOverflowBuffer(child, traceRoot, EMPTY_SCOPE, modeMetadata, modeMetadata);
474
+ if (physicalLayout === 'current') {
475
+ const dictionary = currentMixedOp.callsitePlan.localMessageDictionary;
476
+ expect(root._opMetadata._physicalLayoutPlan?.localMessageDictionary).toBe(dictionary);
477
+ expect(child._opMetadata._physicalLayoutPlan?.localMessageDictionary).toBe(dictionary);
478
+ expect(overflow._opMetadata._physicalLayoutPlan?.localMessageDictionary).toBe(dictionary);
479
+ for (const buffer of [root, child, overflow]) {
480
+ expect(Object.hasOwn(buffer, '_messageDictionary')).toBe(false);
481
+ expect('_messageDictionary' in buffer).toBe(false);
482
+ }
483
+ }
484
+ expect(child.constructor).toBe(getWasmSpanBufferClass(schema, family, physicalLayout));
485
+ expect(overflow.constructor).toBe(child.constructor);
486
+ expect(child._descriptor.parent).toBe(root._descriptor);
487
+ expect(overflow._descriptor.parent).toBe(root._descriptor);
488
+ expect(overflow._identityPtr).toBe(child._identityPtr);
489
+ expect(overflow._layout).toBe(child._layout);
490
+ expectWasmFamilyShape(child, family);
491
+ expectWasmFamilyShape(overflow, family);
492
+ expectWasmPhysicalShape(child, physicalLayout);
493
+ expectWasmPhysicalShape(overflow, physicalLayout);
494
+ }
495
+ }
496
+ });
497
+
498
+ it('keeps JS and WASM decoded rows identical across random mixed overflow streams', () => {
499
+ fc.assert(
500
+ fc.property(
501
+ fc.constantFrom<MessagePhysicalLayout>('current', 'specialized', 'packed'),
502
+ fc.array(
503
+ fc.oneof(
504
+ fc.constant({ kind: 'static' as const, text: undefined }),
505
+ fc.record({ kind: fc.constant('dynamic' as const), text: fc.string({ minLength: 1, maxLength: 24 }) }),
506
+ fc.constant({ kind: 'null' as const, text: undefined }),
507
+ ),
508
+ { minLength: CAPACITY, maxLength: 64 },
509
+ ),
510
+ (physicalLayout, operations) => {
511
+ const parityOperations = [
512
+ { kind: 'static' as const, text: undefined },
513
+ { kind: 'null' as const, text: undefined },
514
+ { kind: 'dynamic' as const, text: 'parity raw' },
515
+ ...operations,
516
+ ];
517
+ const modeMetadata =
518
+ physicalLayout === 'current'
519
+ ? currentMixedOp.metadata
520
+ : physicalLayout === 'specialized'
521
+ ? specializedMixedOp.metadata
522
+ : metadata;
523
+ const JsClass = getSpanBufferClass(schema, 'mixed', physicalLayout);
524
+ JsClass.stats.capacity = CAPACITY;
525
+ const jsRoot = createSpanBuffer(
526
+ schema,
527
+ createTestTraceRoot('js-wasm-parity'),
528
+ modeMetadata,
529
+ CAPACITY,
530
+ JsClass,
531
+ );
532
+ const wasmRoot = createBuffer('mixed', physicalLayout, modeMetadata);
533
+ writeEntryType(jsRoot, 0, ENTRY_TYPE_SPAN_START);
534
+ writeEntryType(jsRoot, 1, ENTRY_TYPE_SPAN_OK);
535
+ jsRoot.message(0, 'parity root');
536
+ jsRoot._writeIndex = 2;
537
+ writeEntryType(wasmRoot, 0, ENTRY_TYPE_SPAN_START);
538
+ writeEntryType(wasmRoot, 1, ENTRY_TYPE_SPAN_OK);
539
+ wasmRoot.message(0, 'parity root');
540
+ wasmRoot._writeIndex = 2;
541
+
542
+ let jsSegment: SpanBuffer<typeof schema> = jsRoot;
543
+ let wasmSegment: WasmSpanBufferInstance<typeof schema> = wasmRoot;
544
+ let jsRow = 2;
545
+ let wasmRow = 2;
546
+ const expected: Array<string | undefined> = [];
547
+ for (const operation of parityOperations) {
548
+ if (jsRow === CAPACITY) {
549
+ jsSegment = createOverflowBuffer(jsSegment);
550
+ jsRow = 0;
551
+ }
552
+ if (wasmRow === CAPACITY) {
553
+ wasmSegment = createWasmOverflowBuffer(wasmSegment, traceRoot, EMPTY_SCOPE, modeMetadata, modeMetadata);
554
+ wasmRow = 0;
555
+ }
556
+ const entryType = operation.kind === 'dynamic' ? ENTRY_TYPE_DEBUG : ENTRY_TYPE_INFO;
557
+ writeEntryType(jsSegment, jsRow, entryType);
558
+ writeEntryType(wasmSegment, wasmRow, entryType);
559
+ if (operation.kind === 'static') {
560
+ writeStaticDense(jsSegment, jsRow, entryType, WASM_DENSE_INDEX);
561
+ writeStaticDense(wasmSegment, wasmRow, entryType, WASM_DENSE_INDEX);
562
+ } else if (operation.kind === 'dynamic') {
563
+ jsSegment.message(jsRow, operation.text);
564
+ wasmSegment.message(wasmRow, operation.text);
565
+ }
566
+ expected.push(resolveMessage(jsSegment, jsRow));
567
+ jsSegment._writeIndex = ++jsRow;
568
+ wasmSegment._writeIndex = ++wasmRow;
569
+ }
570
+
571
+ const jsMessages = collectMessages(jsRoot);
572
+ const wasmMessages = collectMessages(wasmRoot);
573
+ expect(wasmMessages).toEqual(jsMessages);
574
+ expect(jsMessages).toEqual(expected);
575
+ for (
576
+ let segment: WasmSpanBufferInstance<typeof schema> | undefined = wasmRoot;
577
+ segment;
578
+ segment = segment._overflow
579
+ ) {
580
+ expectWasmFamilyShape(segment, 'mixed');
581
+ expectWasmPhysicalShape(segment, physicalLayout);
582
+ }
583
+ },
584
+ ),
585
+ { numRuns: 75 },
586
+ );
587
+ });
588
+ });