goscript 0.1.1 → 0.1.2

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 (356) hide show
  1. package/cmd/goscript/cmd-test.go +104 -11
  2. package/cmd/goscript/cmd-test_test.go +1 -1
  3. package/cmd/goscript/cmd_compile.go +9 -0
  4. package/compiler/compile-request.go +31 -0
  5. package/compiler/compiler.go +1 -1
  6. package/compiler/compliance_test.go +0 -2
  7. package/compiler/config.go +2 -0
  8. package/compiler/gotest/package-result.go +2 -0
  9. package/compiler/gotest/request.go +85 -20
  10. package/compiler/gotest/runner.go +733 -96
  11. package/compiler/gotest/runner_test.go +647 -3
  12. package/compiler/lowered-program.go +9 -2
  13. package/compiler/lowering.go +2001 -345
  14. package/compiler/override-facts.go +77 -27
  15. package/compiler/override-registry.go +5 -4
  16. package/compiler/override-registry_test.go +135 -0
  17. package/compiler/package-graph_test.go +62 -7
  18. package/compiler/package-test-graph-variant.go +40 -16
  19. package/compiler/package-test-graph.go +0 -5
  20. package/compiler/package-test-graph_test.go +61 -3
  21. package/compiler/runtime-contract.go +40 -0
  22. package/compiler/semantic-model-types.go +16 -0
  23. package/compiler/semantic-model.go +336 -91
  24. package/compiler/semantic-model_test.go +50 -1
  25. package/compiler/service.go +9 -3
  26. package/compiler/skeleton_test.go +1921 -298
  27. package/compiler/tsworkspace/owner-process-unix_test.go +72 -0
  28. package/compiler/tsworkspace/owner.go +8 -0
  29. package/compiler/tsworkspace/tool-process-other.go +14 -0
  30. package/compiler/tsworkspace/tool-process-unix.go +19 -0
  31. package/compiler/typescript-emitter.go +122 -9
  32. package/dist/gs/builtin/builtin.d.ts +20 -1
  33. package/dist/gs/builtin/builtin.js +246 -26
  34. package/dist/gs/builtin/builtin.js.map +1 -1
  35. package/dist/gs/builtin/channel.d.ts +24 -10
  36. package/dist/gs/builtin/channel.js +107 -25
  37. package/dist/gs/builtin/channel.js.map +1 -1
  38. package/dist/gs/builtin/defer.d.ts +1 -0
  39. package/dist/gs/builtin/defer.js +12 -2
  40. package/dist/gs/builtin/defer.js.map +1 -1
  41. package/dist/gs/builtin/hostio.d.ts +9 -0
  42. package/dist/gs/builtin/hostio.js +25 -0
  43. package/dist/gs/builtin/hostio.js.map +1 -1
  44. package/dist/gs/builtin/map.js +40 -6
  45. package/dist/gs/builtin/map.js.map +1 -1
  46. package/dist/gs/builtin/print.js.map +1 -1
  47. package/dist/gs/builtin/slice.d.ts +43 -9
  48. package/dist/gs/builtin/slice.js +437 -234
  49. package/dist/gs/builtin/slice.js.map +1 -1
  50. package/dist/gs/builtin/type.d.ts +2 -0
  51. package/dist/gs/builtin/type.js +47 -7
  52. package/dist/gs/builtin/type.js.map +1 -1
  53. package/dist/gs/builtin/varRef.d.ts +2 -0
  54. package/dist/gs/builtin/varRef.js.map +1 -1
  55. package/dist/gs/bytes/buffer.gs.js +28 -28
  56. package/dist/gs/bytes/buffer.gs.js.map +1 -1
  57. package/dist/gs/bytes/iter.gs.js +13 -13
  58. package/dist/gs/bytes/iter.gs.js.map +1 -1
  59. package/dist/gs/compress/zlib/index.d.ts +26 -0
  60. package/dist/gs/compress/zlib/index.js +168 -0
  61. package/dist/gs/compress/zlib/index.js.map +1 -0
  62. package/dist/gs/context/context.d.ts +1 -1
  63. package/dist/gs/context/context.js +8 -3
  64. package/dist/gs/context/context.js.map +1 -1
  65. package/dist/gs/crypto/ecdh/index.d.ts +52 -0
  66. package/dist/gs/crypto/ecdh/index.js +226 -0
  67. package/dist/gs/crypto/ecdh/index.js.map +1 -0
  68. package/dist/gs/crypto/ed25519/index.d.ts +34 -0
  69. package/dist/gs/crypto/ed25519/index.js +160 -0
  70. package/dist/gs/crypto/ed25519/index.js.map +1 -0
  71. package/dist/gs/crypto/internal/constanttime/index.d.ts +4 -0
  72. package/dist/gs/crypto/internal/constanttime/index.js +18 -0
  73. package/dist/gs/crypto/internal/constanttime/index.js.map +1 -0
  74. package/dist/gs/crypto/rand/index.d.ts +2 -0
  75. package/dist/gs/crypto/rand/index.js +85 -0
  76. package/dist/gs/crypto/rand/index.js.map +1 -1
  77. package/dist/gs/crypto/sha256/index.d.ts +8 -0
  78. package/dist/gs/crypto/sha256/index.js +118 -0
  79. package/dist/gs/crypto/sha256/index.js.map +1 -0
  80. package/dist/gs/crypto/sha512/index.d.ts +14 -0
  81. package/dist/gs/crypto/sha512/index.js +129 -0
  82. package/dist/gs/crypto/sha512/index.js.map +1 -0
  83. package/dist/gs/encoding/json/index.d.ts +3 -0
  84. package/dist/gs/encoding/json/index.js +15 -0
  85. package/dist/gs/encoding/json/index.js.map +1 -1
  86. package/dist/gs/errors/errors.js +29 -6
  87. package/dist/gs/errors/errors.js.map +1 -1
  88. package/dist/gs/fmt/fmt.js.map +1 -1
  89. package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.d.ts +7 -7
  90. package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.js +52 -18
  91. package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.js.map +1 -1
  92. package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/json/index.js +56 -20
  93. package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/json/index.js.map +1 -1
  94. package/dist/gs/github.com/aperturerobotics/starpc/srpc/index.d.ts +57 -3
  95. package/dist/gs/github.com/aperturerobotics/starpc/srpc/index.js +366 -1
  96. package/dist/gs/github.com/aperturerobotics/starpc/srpc/index.js.map +1 -1
  97. package/dist/gs/github.com/aperturerobotics/util/conc/index.d.ts +20 -0
  98. package/dist/gs/github.com/aperturerobotics/util/conc/index.js +134 -0
  99. package/dist/gs/github.com/aperturerobotics/util/conc/index.js.map +1 -0
  100. package/dist/gs/github.com/aperturerobotics/wasivm/wazero/kernel/runtime/browser/browser.js.map +1 -1
  101. package/dist/gs/github.com/hack-pad/safejs/internal/catch/index.d.ts +3 -0
  102. package/dist/gs/github.com/hack-pad/safejs/internal/catch/index.js +50 -0
  103. package/dist/gs/github.com/hack-pad/safejs/internal/catch/index.js.map +1 -0
  104. package/dist/gs/github.com/klauspost/compress/internal/le/index.js +3 -2
  105. package/dist/gs/github.com/klauspost/compress/internal/le/index.js.map +1 -1
  106. package/dist/gs/github.com/mr-tron/base58/base58/index.d.ts +27 -0
  107. package/dist/gs/github.com/mr-tron/base58/base58/index.js +172 -0
  108. package/dist/gs/github.com/mr-tron/base58/base58/index.js.map +1 -0
  109. package/dist/gs/github.com/zeebo/blake3/internal/consts/index.d.ts +21 -0
  110. package/dist/gs/github.com/zeebo/blake3/internal/consts/index.js +22 -0
  111. package/dist/gs/github.com/zeebo/blake3/internal/consts/index.js.map +1 -0
  112. package/dist/gs/go/token/index.js +11 -4
  113. package/dist/gs/go/token/index.js.map +1 -1
  114. package/dist/gs/hash/fnv/index.d.ts +57 -0
  115. package/dist/gs/hash/fnv/index.js +299 -0
  116. package/dist/gs/hash/fnv/index.js.map +1 -0
  117. package/dist/gs/hash/index.d.ts +17 -0
  118. package/dist/gs/hash/index.js +94 -0
  119. package/dist/gs/hash/index.js.map +1 -0
  120. package/dist/gs/io/fs/readlink.js +2 -6
  121. package/dist/gs/io/fs/readlink.js.map +1 -1
  122. package/dist/gs/io/fs/walk.js.map +1 -1
  123. package/dist/gs/io/io.js.map +1 -1
  124. package/dist/gs/iter/iter.d.ts +3 -2
  125. package/dist/gs/iter/iter.js.map +1 -1
  126. package/dist/gs/maps/iter.d.ts +5 -5
  127. package/dist/gs/maps/iter.js +48 -21
  128. package/dist/gs/maps/iter.js.map +1 -1
  129. package/dist/gs/maps/maps.d.ts +6 -6
  130. package/dist/gs/math/bits/index.js +14 -24
  131. package/dist/gs/math/bits/index.js.map +1 -1
  132. package/dist/gs/mime/index.js +3 -1
  133. package/dist/gs/mime/index.js.map +1 -1
  134. package/dist/gs/net/http/httptest/index.d.ts +20 -1
  135. package/dist/gs/net/http/httptest/index.js +83 -3
  136. package/dist/gs/net/http/httptest/index.js.map +1 -1
  137. package/dist/gs/net/http/index.d.ts +110 -6
  138. package/dist/gs/net/http/index.js +262 -16
  139. package/dist/gs/net/http/index.js.map +1 -1
  140. package/dist/gs/net/http/pprof/index.d.ts +8 -0
  141. package/dist/gs/net/http/pprof/index.js +59 -0
  142. package/dist/gs/net/http/pprof/index.js.map +1 -0
  143. package/dist/gs/os/error.gs.js +9 -7
  144. package/dist/gs/os/error.gs.js.map +1 -1
  145. package/dist/gs/os/types_js.gs.js +95 -15
  146. package/dist/gs/os/types_js.gs.js.map +1 -1
  147. package/dist/gs/path/filepath/match.js.map +1 -1
  148. package/dist/gs/path/filepath/path.d.ts +5 -3
  149. package/dist/gs/path/filepath/path.js +65 -10
  150. package/dist/gs/path/filepath/path.js.map +1 -1
  151. package/dist/gs/reflect/index.d.ts +3 -2
  152. package/dist/gs/reflect/index.js +2 -1
  153. package/dist/gs/reflect/index.js.map +1 -1
  154. package/dist/gs/reflect/iter.js +2 -2
  155. package/dist/gs/reflect/iter.js.map +1 -1
  156. package/dist/gs/reflect/map.js +26 -0
  157. package/dist/gs/reflect/map.js.map +1 -1
  158. package/dist/gs/reflect/type.d.ts +24 -5
  159. package/dist/gs/reflect/type.js +390 -38
  160. package/dist/gs/reflect/type.js.map +1 -1
  161. package/dist/gs/reflect/types.d.ts +1 -0
  162. package/dist/gs/reflect/types.js +3 -1
  163. package/dist/gs/reflect/types.js.map +1 -1
  164. package/dist/gs/reflect/value.d.ts +4 -1
  165. package/dist/gs/reflect/value.js +39 -1
  166. package/dist/gs/reflect/value.js.map +1 -1
  167. package/dist/gs/reflect/visiblefields.js +1 -1
  168. package/dist/gs/reflect/visiblefields.js.map +1 -1
  169. package/dist/gs/runtime/debug/index.d.ts +39 -0
  170. package/dist/gs/runtime/debug/index.js +58 -0
  171. package/dist/gs/runtime/debug/index.js.map +1 -1
  172. package/dist/gs/runtime/pprof/index.d.ts +20 -0
  173. package/dist/gs/runtime/pprof/index.js +85 -0
  174. package/dist/gs/runtime/pprof/index.js.map +1 -0
  175. package/dist/gs/runtime/trace/index.d.ts +19 -0
  176. package/dist/gs/runtime/trace/index.js +64 -0
  177. package/dist/gs/runtime/trace/index.js.map +1 -0
  178. package/dist/gs/slices/slices.d.ts +24 -9
  179. package/dist/gs/slices/slices.js +229 -24
  180. package/dist/gs/slices/slices.js.map +1 -1
  181. package/dist/gs/sort/slice.gs.d.ts +5 -3
  182. package/dist/gs/sort/slice.gs.js +55 -17
  183. package/dist/gs/sort/slice.gs.js.map +1 -1
  184. package/dist/gs/strings/builder.js +26 -17
  185. package/dist/gs/strings/builder.js.map +1 -1
  186. package/dist/gs/strings/iter.js +140 -75
  187. package/dist/gs/strings/iter.js.map +1 -1
  188. package/dist/gs/strings/replace.js +2 -2
  189. package/dist/gs/strings/replace.js.map +1 -1
  190. package/dist/gs/strings/strings.js +52 -6
  191. package/dist/gs/strings/strings.js.map +1 -1
  192. package/dist/gs/sync/sync.d.ts +6 -3
  193. package/dist/gs/sync/sync.js +39 -11
  194. package/dist/gs/sync/sync.js.map +1 -1
  195. package/dist/gs/syscall/errors.d.ts +116 -112
  196. package/dist/gs/syscall/errors.js +38 -1
  197. package/dist/gs/syscall/errors.js.map +1 -1
  198. package/dist/gs/syscall/fs.d.ts +2 -8
  199. package/dist/gs/syscall/fs.js.map +1 -1
  200. package/dist/gs/syscall/js/index.js +20 -12
  201. package/dist/gs/syscall/js/index.js.map +1 -1
  202. package/dist/gs/syscall/types.d.ts +4 -1
  203. package/dist/gs/syscall/types.js.map +1 -1
  204. package/dist/gs/testing/testing.d.ts +4 -3
  205. package/dist/gs/testing/testing.js +21 -4
  206. package/dist/gs/testing/testing.js.map +1 -1
  207. package/dist/gs/time/time.js +22 -0
  208. package/dist/gs/time/time.js.map +1 -1
  209. package/dist/gs/unicode/unicode.js.map +1 -1
  210. package/dist/gs/unique/index.js +7 -2
  211. package/dist/gs/unique/index.js.map +1 -1
  212. package/go.mod +8 -8
  213. package/go.sum +14 -23
  214. package/gs/builtin/builtin.ts +364 -37
  215. package/gs/builtin/channel.ts +161 -29
  216. package/gs/builtin/defer.ts +13 -2
  217. package/gs/builtin/hostio.test.ts +1 -0
  218. package/gs/builtin/hostio.ts +38 -0
  219. package/gs/builtin/map.ts +46 -6
  220. package/gs/builtin/print.ts +12 -3
  221. package/gs/builtin/runtime-contract.test.ts +257 -10
  222. package/gs/builtin/slice.test.ts +70 -0
  223. package/gs/builtin/slice.ts +566 -255
  224. package/gs/builtin/type.ts +53 -9
  225. package/gs/builtin/varRef.ts +2 -0
  226. package/gs/bytes/buffer.gs.ts +28 -28
  227. package/gs/bytes/iter.gs.ts +13 -14
  228. package/gs/compress/zlib/index.test.ts +28 -0
  229. package/gs/compress/zlib/index.ts +200 -0
  230. package/gs/compress/zlib/meta.json +3 -0
  231. package/gs/context/context.test.ts +31 -1
  232. package/gs/context/context.ts +9 -4
  233. package/gs/crypto/ecdh/index.test.ts +43 -0
  234. package/gs/crypto/ecdh/index.ts +274 -0
  235. package/gs/crypto/ed25519/index.test.ts +41 -0
  236. package/gs/crypto/ed25519/index.ts +238 -0
  237. package/gs/crypto/ed25519/meta.json +13 -0
  238. package/gs/crypto/internal/constanttime/index.test.ts +25 -0
  239. package/gs/crypto/internal/constanttime/index.ts +22 -0
  240. package/gs/crypto/rand/index.test.ts +89 -1
  241. package/gs/crypto/rand/index.ts +103 -1
  242. package/gs/crypto/rand/meta.json +4 -1
  243. package/gs/crypto/sha256/index.test.ts +78 -0
  244. package/gs/crypto/sha256/index.ts +150 -0
  245. package/gs/crypto/sha256/meta.json +9 -0
  246. package/gs/crypto/sha512/index.test.ts +31 -0
  247. package/gs/crypto/sha512/index.ts +161 -0
  248. package/gs/crypto/sha512/meta.json +11 -0
  249. package/gs/encoding/json/index.test.ts +25 -3
  250. package/gs/encoding/json/index.ts +21 -3
  251. package/gs/errors/errors.test.ts +4 -1
  252. package/gs/errors/errors.ts +32 -8
  253. package/gs/fmt/fmt.test.ts +3 -1
  254. package/gs/fmt/fmt.ts +1 -5
  255. package/gs/github.com/aperturerobotics/protobuf-go-lite/index.test.ts +62 -7
  256. package/gs/github.com/aperturerobotics/protobuf-go-lite/index.ts +78 -36
  257. package/gs/github.com/aperturerobotics/protobuf-go-lite/json/index.test.ts +32 -11
  258. package/gs/github.com/aperturerobotics/protobuf-go-lite/json/index.ts +122 -43
  259. package/gs/github.com/aperturerobotics/starpc/srpc/index.test.ts +31 -0
  260. package/gs/github.com/aperturerobotics/starpc/srpc/index.ts +518 -4
  261. package/gs/github.com/aperturerobotics/starpc/srpc/meta.json +6 -0
  262. package/gs/github.com/aperturerobotics/util/conc/index.test.ts +30 -0
  263. package/gs/github.com/aperturerobotics/util/conc/index.ts +172 -0
  264. package/gs/github.com/aperturerobotics/util/conc/meta.json +9 -0
  265. package/gs/github.com/aperturerobotics/wasivm/wazero/kernel/runtime/browser/browser.ts +1 -4
  266. package/gs/github.com/hack-pad/safejs/internal/catch/index.test.ts +35 -0
  267. package/gs/github.com/hack-pad/safejs/internal/catch/index.ts +65 -0
  268. package/gs/github.com/hack-pad/safejs/internal/catch/meta.json +9 -0
  269. package/gs/github.com/klauspost/compress/internal/le/index.test.ts +2 -1
  270. package/gs/github.com/klauspost/compress/internal/le/index.ts +6 -5
  271. package/gs/github.com/mr-tron/base58/base58/index.test.ts +70 -0
  272. package/gs/github.com/mr-tron/base58/base58/index.ts +231 -0
  273. package/gs/github.com/mr-tron/base58/base58/meta.json +3 -0
  274. package/gs/github.com/zeebo/blake3/internal/consts/index.test.ts +46 -0
  275. package/gs/github.com/zeebo/blake3/internal/consts/index.ts +26 -0
  276. package/gs/go/token/index.ts +17 -4
  277. package/gs/hash/fnv/index.test.ts +67 -0
  278. package/gs/hash/fnv/index.ts +351 -0
  279. package/gs/hash/fnv/meta.json +3 -0
  280. package/gs/hash/index.test.ts +37 -0
  281. package/gs/hash/index.ts +118 -0
  282. package/gs/hash/meta.json +5 -0
  283. package/gs/internal/byteorder/index.test.ts +6 -6
  284. package/gs/io/fs/readlink.ts +40 -48
  285. package/gs/io/fs/walk.ts +10 -2
  286. package/gs/io/io.ts +4 -1
  287. package/gs/iter/iter.ts +8 -2
  288. package/gs/maps/iter.ts +69 -26
  289. package/gs/maps/maps.test.ts +23 -0
  290. package/gs/maps/maps.ts +6 -6
  291. package/gs/math/bits/index.test.ts +20 -0
  292. package/gs/math/bits/index.ts +15 -28
  293. package/gs/mime/index.ts +8 -2
  294. package/gs/net/http/httptest/index.test.ts +53 -0
  295. package/gs/net/http/httptest/index.ts +98 -3
  296. package/gs/net/http/index.test.ts +129 -1
  297. package/gs/net/http/index.ts +370 -19
  298. package/gs/net/http/meta.json +6 -0
  299. package/gs/net/http/pprof/index.test.ts +47 -0
  300. package/gs/net/http/pprof/index.ts +65 -0
  301. package/gs/os/error.gs.ts +9 -10
  302. package/gs/os/error.test.ts +41 -0
  303. package/gs/os/file_unix_js.test.ts +55 -0
  304. package/gs/os/tempfile.gs.test.ts +37 -10
  305. package/gs/os/types_js.gs.ts +94 -15
  306. package/gs/path/filepath/match.ts +4 -1
  307. package/gs/path/filepath/meta.json +6 -0
  308. package/gs/path/filepath/path.test.ts +57 -2
  309. package/gs/path/filepath/path.ts +91 -12
  310. package/gs/reflect/field.test.ts +63 -0
  311. package/gs/reflect/index.ts +4 -1
  312. package/gs/reflect/iter.ts +2 -2
  313. package/gs/reflect/map.test.ts +24 -2
  314. package/gs/reflect/map.ts +35 -0
  315. package/gs/reflect/type.ts +543 -60
  316. package/gs/reflect/typefor.test.ts +100 -0
  317. package/gs/reflect/types.ts +3 -1
  318. package/gs/reflect/value.ts +50 -1
  319. package/gs/reflect/visiblefields.ts +1 -1
  320. package/gs/runtime/debug/index.test.ts +22 -1
  321. package/gs/runtime/debug/index.ts +88 -0
  322. package/gs/runtime/pprof/index.test.ts +36 -0
  323. package/gs/runtime/pprof/index.ts +104 -0
  324. package/gs/runtime/pprof/meta.json +6 -0
  325. package/gs/runtime/trace/index.test.ts +45 -0
  326. package/gs/runtime/trace/index.ts +97 -0
  327. package/gs/runtime/trace/meta.json +7 -0
  328. package/gs/slices/meta.json +2 -1
  329. package/gs/slices/slices.test.ts +86 -0
  330. package/gs/slices/slices.ts +284 -37
  331. package/gs/sort/slice.gs.ts +73 -23
  332. package/gs/sort/slice.test.ts +40 -0
  333. package/gs/strings/builder.test.ts +8 -0
  334. package/gs/strings/builder.ts +29 -17
  335. package/gs/strings/iter.test.ts +5 -7
  336. package/gs/strings/iter.ts +146 -71
  337. package/gs/strings/replace.test.ts +1 -4
  338. package/gs/strings/replace.ts +6 -6
  339. package/gs/strings/strings.test.ts +4 -0
  340. package/gs/strings/strings.ts +54 -6
  341. package/gs/sync/sync.test.ts +57 -1
  342. package/gs/sync/sync.ts +45 -13
  343. package/gs/syscall/errors.ts +158 -115
  344. package/gs/syscall/fs.ts +8 -8
  345. package/gs/syscall/js/index.ts +49 -22
  346. package/gs/syscall/net.test.ts +26 -0
  347. package/gs/syscall/types.ts +7 -2
  348. package/gs/testing/testing.test.ts +56 -0
  349. package/gs/testing/testing.ts +27 -10
  350. package/gs/time/meta.json +2 -2
  351. package/gs/time/time.test.ts +4 -0
  352. package/gs/time/time.ts +33 -2
  353. package/gs/unicode/unicode.test.ts +14 -3
  354. package/gs/unicode/unicode.ts +1 -5
  355. package/gs/unique/index.ts +9 -2
  356. package/package.json +3 -3
@@ -1,4 +1,60 @@
1
- import { varRef, type VarRef } from './varRef.js'
1
+ import { isVarRef, varRef, type VarRef } from './varRef.js'
2
+
3
+ export class GoBinaryString extends String {
4
+ readonly bytes: Uint8Array
5
+
6
+ constructor(bytes: Uint8Array) {
7
+ super(bytesToBinaryString(bytes))
8
+ this.bytes = bytes.slice()
9
+ }
10
+
11
+ toString(): string {
12
+ return bytesToBinaryString(this.bytes)
13
+ }
14
+
15
+ valueOf(): string {
16
+ return this.toString()
17
+ }
18
+
19
+ [Symbol.toPrimitive](): string {
20
+ return this.toString()
21
+ }
22
+ }
23
+
24
+ type GoStringValue = string | GoBinaryString
25
+ type GoStringBytes = GoStringValue | Slice<number> | Uint8Array
26
+
27
+ function isGoStringValue(value: unknown): value is GoStringValue {
28
+ return typeof value === 'string' || value instanceof GoBinaryString
29
+ }
30
+
31
+ function goStringBytes(str: GoStringValue): Uint8Array {
32
+ if (str instanceof GoBinaryString) {
33
+ return str.bytes.slice()
34
+ }
35
+ return new TextEncoder().encode(str)
36
+ }
37
+
38
+ function goStringComparableBytes(value: GoStringBytes): Uint8Array {
39
+ if (isGoStringValue(value)) {
40
+ return goStringBytes(value)
41
+ }
42
+ if (value instanceof Uint8Array) {
43
+ return value
44
+ }
45
+ if (value === null || value === undefined) {
46
+ return new Uint8Array(0)
47
+ }
48
+ return Uint8Array.from(asArray(value))
49
+ }
50
+
51
+ function goStringFromBytes(bytes: Uint8Array): string {
52
+ try {
53
+ return new TextDecoder('utf-8', { fatal: true }).decode(bytes)
54
+ } catch {
55
+ return new GoBinaryString(bytes) as unknown as string
56
+ }
57
+ }
2
58
 
3
59
  /**
4
60
  * GoSliceObject contains metadata for complex slice views
@@ -8,6 +64,7 @@ interface GoSliceObject<T> {
8
64
  offset: number // Offset into the backing array
9
65
  length: number // Length of the slice
10
66
  capacity: number // Capacity of the slice
67
+ target?: T[] // Materialized proxy target for JS array operations
11
68
  }
12
69
 
13
70
  const addressStride = 0x100000000
@@ -21,6 +78,25 @@ export type SliceProxy<T> = T[] & {
21
78
  __meta__: GoSliceObject<T>
22
79
  }
23
80
 
81
+ type ByteSlice = Uint8Array & {
82
+ __meta__?: GoSliceObject<number>
83
+ }
84
+
85
+ function sliceIndexProperty(prop: string | symbol): number {
86
+ if (typeof prop !== 'string' || prop.length === 0) {
87
+ return -1
88
+ }
89
+ let index = 0
90
+ for (let i = 0; i < prop.length; i++) {
91
+ const digit = prop.charCodeAt(i) - 48
92
+ if (digit < 0 || digit > 9) {
93
+ return -1
94
+ }
95
+ index = index * 10 + digit
96
+ }
97
+ return index
98
+ }
99
+
24
100
  /**
25
101
  * Slice<T> is a union type that is either a plain array or a proxy
26
102
  * null represents the nil state.
@@ -38,39 +114,41 @@ export type Slice<T> =
38
114
  * and route it through the backing array.
39
115
  */
40
116
  function wrapSliceProxy<T>(proxy: SliceProxy<T>): SliceProxy<T> {
117
+ const meta = proxy.__meta__
118
+ meta.target = proxy
41
119
  const handler = {
42
120
  get(target: any, prop: string | symbol): any {
43
- if (typeof prop === 'string' && /^\d+$/.test(prop)) {
44
- const index = Number(prop)
45
- if (index >= 0 && index < target.__meta__.length) {
46
- return target.__meta__.backing[target.__meta__.offset + index]
121
+ const index = sliceIndexProperty(prop)
122
+ if (index >= 0) {
123
+ if (index < meta.length) {
124
+ return meta.backing[meta.offset + index]
47
125
  }
48
126
  throw new Error(
49
- `Slice index out of range: ${index} >= ${target.__meta__.length}`,
127
+ `Slice index out of range: ${index} >= ${meta.length}`,
50
128
  )
51
129
  }
52
130
 
53
131
  if (prop === 'length') {
54
- return target.__meta__.length
132
+ return meta.length
55
133
  }
56
134
 
57
135
  if (prop === '__meta__') {
58
- return target.__meta__
136
+ return meta
59
137
  }
60
138
 
61
139
  return Reflect.get(target, prop)
62
140
  },
63
141
 
64
142
  set(target: any, prop: string | symbol, value: any): boolean {
65
- if (typeof prop === 'string' && /^\d+$/.test(prop)) {
66
- const index = Number(prop)
67
- if (index >= 0 && index < target.__meta__.length) {
68
- target.__meta__.backing[target.__meta__.offset + index] = value
143
+ const index = sliceIndexProperty(prop)
144
+ if (index >= 0) {
145
+ if (index < meta.length) {
146
+ meta.backing[meta.offset + index] = value
69
147
  target[index] = value // Also update the proxy target for consistency
70
148
  return true
71
149
  }
72
150
  throw new Error(
73
- `Slice index out of range: ${index} >= ${target.__meta__.length}`,
151
+ `Slice index out of range: ${index} >= ${meta.length}`,
74
152
  )
75
153
  }
76
154
 
@@ -85,6 +163,24 @@ function wrapSliceProxy<T>(proxy: SliceProxy<T>): SliceProxy<T> {
85
163
  return new Proxy(proxy, handler) as SliceProxy<T>
86
164
  }
87
165
 
166
+ function sliceProxyFromBacking<T>(
167
+ backing: T[],
168
+ offset: number,
169
+ length: number,
170
+ capacity: number,
171
+ target?: T[],
172
+ ): SliceProxy<T> {
173
+ const proxyTargetArray = (target ?? new Array<T>(length)) as SliceProxy<T>
174
+ proxyTargetArray.length = length
175
+ if (target === undefined) {
176
+ for (let i = 0; i < length; i++) {
177
+ proxyTargetArray[i] = backing[offset + i]
178
+ }
179
+ }
180
+ proxyTargetArray.__meta__ = { backing, offset, length, capacity }
181
+ return wrapSliceProxy(proxyTargetArray)
182
+ }
183
+
88
184
  // asArray converts a slice to a JavaScript array.
89
185
  export function asArray<T>(slice: Slice<T>): T[] {
90
186
  if (slice === null || slice === undefined) {
@@ -121,7 +217,9 @@ export function sliceToArray<T>(
121
217
  )
122
218
  }
123
219
  if (typeHint === 'byte') {
124
- return new Uint8Array(asArray(slice as Slice<T>).slice(0, length) as number[])
220
+ return new Uint8Array(
221
+ asArray(slice as Slice<T>).slice(0, length) as number[],
222
+ )
125
223
  }
126
224
  return asArray(slice as Slice<T>).slice(0, length)
127
225
  }
@@ -140,7 +238,9 @@ export function sliceToArrayPointer<T>(
140
238
  if (slice instanceof Uint8Array) {
141
239
  return varRef(goSlice(slice, 0, length) as unknown as Uint8Array)
142
240
  }
143
- return varRef(goSlice(slice as Slice<T>, 0, length) as unknown as Uint8Array)
241
+ return varRef(
242
+ goSlice(slice as Slice<T>, 0, length) as unknown as Uint8Array,
243
+ )
144
244
  }
145
245
  if (slice instanceof Uint8Array) {
146
246
  return varRef(goSlice(slice, 0, length) as unknown as T[])
@@ -168,6 +268,28 @@ function normalizeSliceIndex(value: number | undefined): number | undefined {
168
268
  return Number(value)
169
269
  }
170
270
 
271
+ function byteSliceMeta(slice: Uint8Array): GoSliceObject<number> | undefined {
272
+ return (slice as ByteSlice).__meta__
273
+ }
274
+
275
+ function byteSliceView(
276
+ backing: Uint8Array,
277
+ offset: number,
278
+ length: number,
279
+ capacity: number,
280
+ ): Uint8Array {
281
+ const view = backing.subarray(offset, offset + length) as ByteSlice
282
+ if (capacity !== length) {
283
+ view.__meta__ = {
284
+ backing: backing as unknown as number[],
285
+ offset,
286
+ length,
287
+ capacity,
288
+ }
289
+ }
290
+ return view
291
+ }
292
+
171
293
  /**
172
294
  * isSliceProxy checks if a slice is a SliceProxy (has __meta__ property)
173
295
  * This is an alias for isComplexSlice for better type hinting
@@ -201,24 +323,7 @@ export const makeSlice = <T>(
201
323
  return new Uint8Array(length) as Slice<T>
202
324
  }
203
325
 
204
- // If capacity > length, create a SliceProxy backed by a Uint8Array
205
- const backingUint8 = new Uint8Array(actualCapacity)
206
- const backingNumbers = Array.from(backingUint8) as T[] // Convert to number[] for backing
207
-
208
- const proxyTargetArray = new Array<T>(length)
209
- for (let i = 0; i < length; i++) {
210
- proxyTargetArray[i] = 0 as T // Initialize with zeros
211
- }
212
-
213
- const proxy = proxyTargetArray as SliceProxy<T>
214
- proxy.__meta__ = {
215
- backing: backingNumbers,
216
- offset: 0,
217
- length: length,
218
- capacity: actualCapacity,
219
- }
220
-
221
- return wrapSliceProxy(proxy) as Slice<T>
326
+ return byteSliceView(new Uint8Array(actualCapacity), 0, length, actualCapacity) as Slice<T>
222
327
  }
223
328
 
224
329
  const actualCapacity = capacity === undefined ? length : capacity
@@ -245,12 +350,11 @@ export const makeSlice = <T>(
245
350
  }
246
351
 
247
352
  const backingArr = new Array<T>(actualCapacity)
248
- // Initialize the relevant part of the backing array
249
- for (let i = 0; i < length; i++) {
353
+ // Go zero-initializes the whole backing array. Elements beyond len become
354
+ // observable when a slice is resliced up to cap.
355
+ for (let i = 0; i < actualCapacity; i++) {
250
356
  backingArr[i] = zeroValue()
251
357
  }
252
- // The rest of backingArr (from length to actualCapacity-1) remains uninitialized (undefined),
253
- // representing available capacity.
254
358
 
255
359
  // OPTIMIZATION: If length equals capacity, return backing array directly
256
360
  if (length === actualCapacity) {
@@ -275,9 +379,9 @@ export const makeSlice = <T>(
275
379
  // Create a proper Proxy with the handler for SliceProxy behavior
276
380
  const handler = {
277
381
  get(target: any, prop: string | symbol): any {
278
- if (typeof prop === 'string' && /^\d+$/.test(prop)) {
279
- const index = Number(prop)
280
- if (index >= 0 && index < target.__meta__.length) {
382
+ const index = sliceIndexProperty(prop)
383
+ if (index >= 0) {
384
+ if (index < target.__meta__.length) {
281
385
  return target.__meta__.backing[target.__meta__.offset + index]
282
386
  }
283
387
  throw new Error(
@@ -297,9 +401,9 @@ export const makeSlice = <T>(
297
401
  },
298
402
 
299
403
  set(target: any, prop: string | symbol, value: any): boolean {
300
- if (typeof prop === 'string' && /^\d+$/.test(prop)) {
301
- const index = Number(prop)
302
- if (index >= 0 && index < target.__meta__.length) {
404
+ const index = sliceIndexProperty(prop)
405
+ if (index >= 0) {
406
+ if (index < target.__meta__.length) {
303
407
  target.__meta__.backing[target.__meta__.offset + index] = value
304
408
  target[index] = value // Also update the proxy target for consistency
305
409
  return true
@@ -349,15 +453,16 @@ export function goSlice<T>( // T can be number for Uint8Array case
349
453
  high?: number,
350
454
  max?: number,
351
455
  ): Slice<T> {
456
+ s = collectionValue(s) as Slice<T> | Uint8Array
352
457
  low = normalizeSliceIndex(low)
353
458
  high = normalizeSliceIndex(high)
354
459
  max = normalizeSliceIndex(max)
355
460
 
356
461
  const handler = {
357
462
  get(target: any, prop: string | symbol): any {
358
- if (typeof prop === 'string' && /^\d+$/.test(prop)) {
359
- const index = Number(prop)
360
- if (index >= 0 && index < target.__meta__.length) {
463
+ const index = sliceIndexProperty(prop)
464
+ if (index >= 0) {
465
+ if (index < target.__meta__.length) {
361
466
  return target.__meta__.backing[target.__meta__.offset + index]
362
467
  }
363
468
  throw new Error(
@@ -392,9 +497,9 @@ export function goSlice<T>( // T can be number for Uint8Array case
392
497
  },
393
498
 
394
499
  set(target: any, prop: string | symbol, value: any): boolean {
395
- if (typeof prop === 'string' && /^\d+$/.test(prop)) {
396
- const index = Number(prop)
397
- if (index >= 0 && index < target.__meta__.length) {
500
+ const index = sliceIndexProperty(prop)
501
+ if (index >= 0) {
502
+ if (index < target.__meta__.length) {
398
503
  target.__meta__.backing[target.__meta__.offset + index] = value
399
504
  target[index] = value
400
505
  return true
@@ -422,55 +527,51 @@ export function goSlice<T>( // T can be number for Uint8Array case
422
527
  }
423
528
 
424
529
  if (s instanceof Uint8Array) {
530
+ const meta = byteSliceMeta(s)
531
+ const metaBacking = meta?.backing as unknown
532
+ const backing =
533
+ metaBacking instanceof Uint8Array ? metaBacking : s
534
+ const baseOffset = meta?.offset ?? 0
535
+ const baseCapacity = meta?.capacity ?? s.length
425
536
  const actualLow = low ?? 0
426
537
  const actualHigh = high ?? s.length
427
538
 
428
- if (actualLow < 0 || actualHigh < actualLow || actualHigh > s.length) {
539
+ if (
540
+ actualLow < 0 ||
541
+ actualHigh < actualLow ||
542
+ actualLow > baseCapacity ||
543
+ actualHigh > baseCapacity
544
+ ) {
429
545
  throw new Error(
430
- `Invalid slice indices: low ${actualLow}, high ${actualHigh} for Uint8Array of length ${s.length}`,
546
+ `Invalid slice indices: low ${actualLow}, high ${actualHigh} for Uint8Array with capacity ${baseCapacity}`,
431
547
  )
432
548
  }
433
549
 
434
550
  const newLength = actualHigh - actualLow
435
551
 
436
552
  if (max !== undefined) {
437
- if (max < actualHigh || max > s.length) {
553
+ if (max < actualHigh || max > baseCapacity) {
438
554
  // max is relative to the original s.length (capacity)
439
555
  throw new Error(
440
- `Invalid max index: ${max}. Constraints: low ${actualLow} <= high ${actualHigh} <= max <= original_length ${s.length}`,
556
+ `Invalid max index: ${max}. Constraints: low ${actualLow} <= high ${actualHigh} <= max <= capacity ${baseCapacity}`,
441
557
  )
442
558
  }
443
559
 
444
560
  const newCap = max - actualLow // Capacity of the new slice view
445
-
446
- if (newCap !== newLength) {
447
- const proxyTarget = new Array<number>(newLength) as SliceProxy<number>
448
- proxyTarget.__meta__ = {
449
- backing: s as unknown as number[],
450
- offset: actualLow,
451
- length: newLength,
452
- capacity: newCap,
453
- }
454
- return new Proxy(proxyTarget, handler) as unknown as Slice<T>
455
- } else {
456
- // newCap === newLength, standard Uint8Array is fine.
457
- return s.subarray(actualLow, actualHigh) as Slice<T> // T is number
458
- }
561
+ return byteSliceView(
562
+ backing,
563
+ baseOffset + actualLow,
564
+ newLength,
565
+ newCap,
566
+ ) as Slice<T>
459
567
  }
460
568
 
461
- if (actualHigh !== s.length) {
462
- const proxyTarget = new Array<number>(newLength) as SliceProxy<number>
463
- proxyTarget.__meta__ = {
464
- backing: s as unknown as number[],
465
- offset: actualLow,
466
- length: newLength,
467
- capacity: s.length - actualLow,
468
- }
469
- return new Proxy(proxyTarget, handler) as unknown as Slice<T>
470
- }
471
-
472
- // max is not defined and length equals capacity, return the Uint8Array view directly.
473
- return s.subarray(actualLow, actualHigh) as Slice<T> // T is number
569
+ return byteSliceView(
570
+ backing,
571
+ baseOffset + actualLow,
572
+ newLength,
573
+ baseCapacity - actualLow,
574
+ ) as Slice<T>
474
575
  }
475
576
 
476
577
  // Handle nil slices - in Go, slicing a nil slice with valid bounds returns nil
@@ -561,7 +662,7 @@ export function goSlice<T>( // T can be number for Uint8Array case
561
662
  const newOffset = oldOffset + low
562
663
 
563
664
  // OPTIMIZATION: If the result would have offset=0 and length=capacity, return backing directly
564
- if (newOffset === 0 && newLength === newCap) {
665
+ if (newOffset === 0 && newLength === newCap && backing.length === newLength) {
565
666
  return backing as Slice<T>
566
667
  }
567
668
 
@@ -615,9 +716,9 @@ export const arrayToSlice = <T>(
615
716
 
616
717
  const handler = {
617
718
  get(target: any, prop: string | symbol): any {
618
- if (typeof prop === 'string' && /^\d+$/.test(prop)) {
619
- const index = Number(prop)
620
- if (index >= 0 && index < target.__meta__.length) {
719
+ const index = sliceIndexProperty(prop)
720
+ if (index >= 0) {
721
+ if (index < target.__meta__.length) {
621
722
  return target.__meta__.backing[target.__meta__.offset + index]
622
723
  }
623
724
  throw new Error(
@@ -652,9 +753,9 @@ export const arrayToSlice = <T>(
652
753
  },
653
754
 
654
755
  set(target: any, prop: string | symbol, value: any): boolean {
655
- if (typeof prop === 'string' && /^\d+$/.test(prop)) {
656
- const index = Number(prop)
657
- if (index >= 0 && index < target.__meta__.length) {
756
+ const index = sliceIndexProperty(prop)
757
+ if (index >= 0) {
758
+ if (index < target.__meta__.length) {
658
759
  target.__meta__.backing[target.__meta__.offset + index] = value
659
760
  return true
660
761
  }
@@ -699,7 +800,7 @@ export const arrayToSlice = <T>(
699
800
  */
700
801
  export const len = <T = unknown, V = unknown>(
701
802
  obj:
702
- | string
803
+ | GoStringValue
703
804
  | Array<T>
704
805
  | Slice<T>
705
806
  | Map<T, V>
@@ -709,32 +810,41 @@ export const len = <T = unknown, V = unknown>(
709
810
  | null
710
811
  | undefined,
711
812
  ): number => {
813
+ obj = collectionValue(obj) as typeof obj
712
814
  if (obj === null || obj === undefined) {
713
815
  return 0
714
816
  }
715
817
 
716
818
  if (typeof obj === 'string') {
717
- return stringLen(obj) // Call new stringLen for strings
819
+ return stringLen(obj)
718
820
  }
719
821
 
720
- if (obj instanceof Map || obj instanceof Set) {
721
- return obj.size
822
+ if (obj instanceof Uint8Array) {
823
+ return obj.length
722
824
  }
723
825
 
724
- if (obj instanceof Uint8Array) {
826
+ if (Array.isArray(obj)) {
827
+ const meta = (obj as unknown as SliceProxy<T>).__meta__
828
+ if (meta !== undefined) {
829
+ return meta.length
830
+ }
725
831
  return obj.length
726
832
  }
727
833
 
728
- if (typeof (obj as any).len === 'function') {
729
- return (obj as { len(): number }).len()
834
+ if (obj instanceof Map || obj instanceof Set) {
835
+ return obj.size
836
+ }
837
+
838
+ if (obj instanceof GoBinaryString) {
839
+ return stringLen(obj)
730
840
  }
731
841
 
732
842
  if (isComplexSlice(obj as any)) {
733
- return (obj as SliceProxy<T>).__meta__.length
843
+ return (obj as unknown as SliceProxy<T>).__meta__.length
734
844
  }
735
845
 
736
- if (Array.isArray(obj)) {
737
- return obj.length
846
+ if (typeof (obj as any).len === 'function') {
847
+ return (obj as { len(): number }).len()
738
848
  }
739
849
 
740
850
  throw new Error('cannot determine len of this type')
@@ -745,23 +855,30 @@ export const len = <T = unknown, V = unknown>(
745
855
  * @param obj The slice.
746
856
  * @returns The capacity of the slice.
747
857
  */
748
- export const cap = <T>(obj: Slice<T> | Uint8Array): number => {
858
+ export const cap = <T>(
859
+ obj: Slice<T> | Uint8Array | { cap(): number } | null | undefined,
860
+ ): number => {
861
+ obj = collectionValue(obj) as typeof obj
749
862
  if (obj === null || obj === undefined) {
750
863
  return 0
751
864
  }
752
865
 
753
- if (obj instanceof Uint8Array) {
754
- return obj.length // Uint8Array capacity is its length
866
+ if (isComplexSlice(obj as any)) {
867
+ return (obj as SliceProxy<T>).__meta__.capacity
755
868
  }
756
869
 
757
- if (isComplexSlice(obj)) {
758
- return obj.__meta__.capacity
870
+ if (obj instanceof Uint8Array) {
871
+ return obj.length // Uint8Array capacity is its length
759
872
  }
760
873
 
761
874
  if (Array.isArray(obj)) {
762
875
  return obj.length
763
876
  }
764
877
 
878
+ if (typeof (obj as any).cap === 'function') {
879
+ return (obj as { cap(): number }).cap()
880
+ }
881
+
765
882
  return 0
766
883
  }
767
884
 
@@ -776,6 +893,7 @@ export const cap = <T>(obj: Slice<T> | Uint8Array): number => {
776
893
  export function append(slice: Uint8Array, ...elements: any[]): Uint8Array
777
894
  // Overload for null slice with number elements - returns number slice (Bytes compatible)
778
895
  export function append(slice: null, ...elements: number[]): Slice<number>
896
+ export function append<T>(slice: null, ...elements: T[]): Slice<T>
779
897
  export function append<T>(slice: Slice<T>, ...elements: any[]): Slice<T>
780
898
  export function append<T>(
781
899
  slice: Slice<T> | Uint8Array | null,
@@ -788,51 +906,7 @@ export function append<T>(
788
906
 
789
907
  // If producing Uint8Array, all elements must be numbers and potentially flattened from other Uint8Arrays/number slices.
790
908
  if (produceUint8Array) {
791
- let combinedBytes: number[] = []
792
- // Add bytes from the original slice if it exists and is numeric.
793
- if (inputIsUint8Array) {
794
- appendBytes(combinedBytes, slice as Uint8Array)
795
- } else if (slice !== null && slice !== undefined) {
796
- // Original was Slice<number> or number[]
797
- const sliceLen = len(slice)
798
- for (let i = 0; i < sliceLen; i++) {
799
- const val = (slice as any)[i]
800
- if (typeof val !== 'number') {
801
- throw new Error(
802
- 'Cannot produce Uint8Array: original slice contains non-number elements.',
803
- )
804
- }
805
- combinedBytes.push(val)
806
- }
807
- }
808
- // Add bytes from the varargs elements.
809
- // For Uint8Array, elements are always flattened if they are slices/Uint8Arrays.
810
- for (const item of elements) {
811
- if (item instanceof Uint8Array) {
812
- appendBytes(combinedBytes, item)
813
- } else if (isComplexSlice(item) || Array.isArray(item)) {
814
- const itemLen = len(item as Slice<any>)
815
- for (let i = 0; i < itemLen; i++) {
816
- const val = (item as any)[i]
817
- if (typeof val !== 'number') {
818
- throw new Error(
819
- 'Cannot produce Uint8Array: appended elements contain non-numbers.',
820
- )
821
- }
822
- combinedBytes.push(val)
823
- }
824
- } else {
825
- if (typeof item !== 'number') {
826
- throw new Error(
827
- 'Cannot produce Uint8Array: appended elements contain non-numbers.',
828
- )
829
- }
830
- combinedBytes.push(item)
831
- }
832
- }
833
- const newArr = new Uint8Array(combinedBytes.length)
834
- newArr.set(combinedBytes)
835
- return newArr as any
909
+ return appendByteSlice(slice as Uint8Array, elements) as any
836
910
  }
837
911
 
838
912
  // Handle generic Slice<T> (non-Uint8Array result).
@@ -844,28 +918,30 @@ export function append<T>(
844
918
  return slice as any
845
919
  }
846
920
 
847
- let originalElements: T[] = []
921
+ let originalElements: T[] | undefined
922
+ let oldLength = 0
848
923
  let oldCapacity: number
849
924
  let isOriginalComplex = false
850
925
  let originalBacking: T[] | undefined = undefined
926
+ let originalTarget: T[] | undefined = undefined
851
927
  let originalOffset = 0
852
928
 
853
929
  if (slice === null || slice === undefined) {
854
930
  oldCapacity = 0
855
931
  } else if (isComplexSlice(slice)) {
856
932
  const meta = slice.__meta__
857
- for (let i = 0; i < meta.length; i++)
858
- originalElements.push(meta.backing[meta.offset + i])
933
+ oldLength = meta.length
859
934
  oldCapacity = meta.capacity
860
935
  isOriginalComplex = true
861
936
  originalBacking = meta.backing
937
+ originalTarget = meta.target
862
938
  originalOffset = meta.offset
863
939
  } else {
864
940
  // Simple T[] array
865
941
  originalElements = (slice as T[]).slice()
866
- oldCapacity = (slice as T[]).length
942
+ oldLength = originalElements.length
943
+ oldCapacity = oldLength
867
944
  }
868
- const oldLength = originalElements.length
869
945
  const newLength = oldLength + numAdded
870
946
 
871
947
  // Case 1: Modify in-place if original was SliceProxy and has enough capacity.
@@ -873,16 +949,19 @@ export function append<T>(
873
949
  for (let i = 0; i < numAdded; i++) {
874
950
  originalBacking[originalOffset + oldLength + i] = elements[i] as T
875
951
  }
876
- const resultProxy = new Array(newLength) as SliceProxy<T>
877
- for (let i = 0; i < newLength; i++)
878
- resultProxy[i] = originalBacking[originalOffset + i]
879
- resultProxy.__meta__ = {
880
- backing: originalBacking,
881
- offset: originalOffset,
882
- length: newLength,
883
- capacity: oldCapacity,
952
+ const target = originalTarget
953
+ if (target !== undefined) {
954
+ for (let i = 0; i < numAdded; i++) {
955
+ target[oldLength + i] = elements[i] as T
956
+ }
884
957
  }
885
- return wrapSliceProxy(resultProxy) as any
958
+ return sliceProxyFromBacking(
959
+ originalBacking,
960
+ originalOffset,
961
+ newLength,
962
+ oldCapacity,
963
+ target,
964
+ ) as any
886
965
  }
887
966
 
888
967
  // Case 2: Reallocation is needed.
@@ -899,27 +978,86 @@ export function append<T>(
899
978
  }
900
979
 
901
980
  const newBacking = new Array<T>(newCapacity)
902
- for (let i = 0; i < oldLength; i++) {
903
- newBacking[i] = originalElements[i]
981
+ if (isOriginalComplex && originalBacking) {
982
+ for (let i = 0; i < oldLength; i++) {
983
+ newBacking[i] = originalBacking[originalOffset + i]
984
+ }
985
+ } else if (originalElements !== undefined) {
986
+ for (let i = 0; i < oldLength; i++) {
987
+ newBacking[i] = originalElements[i]
988
+ }
904
989
  }
905
990
  for (let i = 0; i < numAdded; i++) {
906
991
  newBacking[oldLength + i] = elements[i] as T
907
992
  }
908
993
 
909
- const resultProxy = new Array(newLength) as SliceProxy<T>
910
- for (let i = 0; i < newLength; i++) resultProxy[i] = newBacking[i]
911
- resultProxy.__meta__ = {
912
- backing: newBacking,
913
- offset: 0,
914
- length: newLength,
915
- capacity: newCapacity,
994
+ return sliceProxyFromBacking(newBacking, 0, newLength, newCapacity) as any
995
+ }
996
+
997
+ function appendByteSlice(slice: Uint8Array, elements: any[]): Uint8Array {
998
+ const meta = byteSliceMeta(slice)
999
+ const metaBacking = meta?.backing as unknown
1000
+ const backing =
1001
+ metaBacking instanceof Uint8Array ? metaBacking : slice
1002
+ const offset = meta?.offset ?? 0
1003
+ const oldLength = slice.length
1004
+ const oldCapacity = meta?.capacity ?? oldLength
1005
+ let added = 0
1006
+ for (const item of elements) {
1007
+ added += byteElementLength(item)
1008
+ }
1009
+ const newLength = oldLength + added
1010
+ if (newLength <= oldCapacity) {
1011
+ const view = byteSliceView(backing, offset, newLength, oldCapacity)
1012
+ writeByteElements(view, oldLength, elements)
1013
+ return view
1014
+ }
1015
+ const next = new Uint8Array(newLength)
1016
+ next.set(slice)
1017
+ writeByteElements(next, oldLength, elements)
1018
+ return next
1019
+ }
1020
+
1021
+ function byteElementLength(item: any): number {
1022
+ if (item instanceof Uint8Array) {
1023
+ return item.length
916
1024
  }
917
- return wrapSliceProxy(resultProxy) as any
1025
+ if (isComplexSlice(item) || Array.isArray(item)) {
1026
+ return len(item as Slice<any>)
1027
+ }
1028
+ if (typeof item !== 'number') {
1029
+ throw new Error('Cannot produce Uint8Array: appended elements contain non-numbers.')
1030
+ }
1031
+ return 1
918
1032
  }
919
1033
 
920
- function appendBytes(dst: number[], src: Uint8Array): void {
921
- for (let i = 0; i < src.length; i++) {
922
- dst.push(src[i])
1034
+ function writeByteElements(dst: Uint8Array, offset: number, elements: any[]): void {
1035
+ let cursor = offset
1036
+ for (const item of elements) {
1037
+ if (item instanceof Uint8Array) {
1038
+ dst.set(item, cursor)
1039
+ cursor += item.length
1040
+ continue
1041
+ }
1042
+ if (isComplexSlice(item) || Array.isArray(item)) {
1043
+ const itemLen = len(item as Slice<any>)
1044
+ for (let i = 0; i < itemLen; i++) {
1045
+ const value = (item as any)[i]
1046
+ if (typeof value !== 'number') {
1047
+ throw new Error(
1048
+ 'Cannot produce Uint8Array: appended elements contain non-numbers.',
1049
+ )
1050
+ }
1051
+ dst[cursor] = value
1052
+ cursor++
1053
+ }
1054
+ continue
1055
+ }
1056
+ if (typeof item !== 'number') {
1057
+ throw new Error('Cannot produce Uint8Array: appended elements contain non-numbers.')
1058
+ }
1059
+ dst[cursor] = item
1060
+ cursor++
923
1061
  }
924
1062
  }
925
1063
 
@@ -935,14 +1073,14 @@ export function copy<T>(dst: Slice<T>, src: Slice<T>): number
935
1073
  export function copy<T>(dst: Slice<T>, src: string): number
936
1074
  export function copy<T>(
937
1075
  dst: Slice<T> | Uint8Array,
938
- src: Slice<T> | Uint8Array | string,
1076
+ src: Slice<T> | Uint8Array | GoStringValue,
939
1077
  ): number {
940
1078
  if (dst === null) {
941
1079
  return 0
942
1080
  }
943
1081
 
944
1082
  // Handle string source first
945
- if (typeof src === 'string') {
1083
+ if (isGoStringValue(src)) {
946
1084
  return copyFromString(dst, src)
947
1085
  }
948
1086
 
@@ -983,9 +1121,13 @@ export function copy<T>(
983
1121
  /**
984
1122
  * Helper: Copy from string to any destination type
985
1123
  */
986
- function copyFromString<T>(dst: Slice<T> | Uint8Array, src: string): number {
1124
+ function copyFromString<T>(
1125
+ dst: Slice<T> | Uint8Array,
1126
+ src: GoStringValue,
1127
+ ): number {
987
1128
  const dstLen = dst instanceof Uint8Array ? dst.length : len(dst)
988
- const count = Math.min(dstLen, src.length)
1129
+ const bytes = goStringBytes(src)
1130
+ const count = Math.min(dstLen, bytes.length)
989
1131
 
990
1132
  if (count === 0) {
991
1133
  return 0
@@ -993,18 +1135,18 @@ function copyFromString<T>(dst: Slice<T> | Uint8Array, src: string): number {
993
1135
 
994
1136
  if (dst instanceof Uint8Array) {
995
1137
  for (let i = 0; i < count; i++) {
996
- dst[i] = src.charCodeAt(i)
1138
+ dst[i] = bytes[i]
997
1139
  }
998
1140
  } else if (isComplexSlice(dst)) {
999
1141
  const dstMeta = dst.__meta__
1000
1142
  for (let i = 0; i < count; i++) {
1001
- const byteVal = src.charCodeAt(i)
1143
+ const byteVal = bytes[i]
1002
1144
  dstMeta.backing[dstMeta.offset + i] = byteVal as unknown as T
1003
1145
  ;(dst as any)[i] = byteVal
1004
1146
  }
1005
1147
  } else if (Array.isArray(dst)) {
1006
1148
  for (let i = 0; i < count; i++) {
1007
- dst[i] = src.charCodeAt(i) as unknown as T
1149
+ dst[i] = bytes[i] as unknown as T
1008
1150
  }
1009
1151
  }
1010
1152
 
@@ -1019,15 +1161,9 @@ function copyToUint8Array(
1019
1161
  src: Slice<number>,
1020
1162
  count: number,
1021
1163
  ): number {
1022
- if (isComplexSlice(src)) {
1023
- const srcMeta = src.__meta__
1024
- for (let i = 0; i < count; i++) {
1025
- dst[i] = srcMeta.backing[srcMeta.offset + i]
1026
- }
1027
- } else if (Array.isArray(src)) {
1028
- for (let i = 0; i < count; i++) {
1029
- dst[i] = src[i]
1030
- }
1164
+ const values = copySliceValues(src, count)
1165
+ for (let i = 0; i < count; i++) {
1166
+ dst[i] = values[i]
1031
1167
  }
1032
1168
  return count
1033
1169
  }
@@ -1040,15 +1176,16 @@ function copyFromUint8Array<T>(
1040
1176
  src: Uint8Array,
1041
1177
  count: number,
1042
1178
  ): number {
1179
+ const values = Array.from(src.subarray(0, count))
1043
1180
  if (isComplexSlice(dst)) {
1044
1181
  const dstMeta = dst.__meta__
1045
1182
  for (let i = 0; i < count; i++) {
1046
- dstMeta.backing[dstMeta.offset + i] = src[i] as unknown as T
1047
- ;(dst as any)[i] = src[i]
1183
+ dstMeta.backing[dstMeta.offset + i] = values[i] as unknown as T
1184
+ ;(dst as any)[i] = values[i]
1048
1185
  }
1049
1186
  } else if (Array.isArray(dst)) {
1050
1187
  for (let i = 0; i < count; i++) {
1051
- dst[i] = src[i] as unknown as T
1188
+ dst[i] = values[i] as unknown as T
1052
1189
  }
1053
1190
  }
1054
1191
  return count
@@ -1062,37 +1199,36 @@ function copyBetweenSlices<T>(
1062
1199
  src: Slice<T>,
1063
1200
  count: number,
1064
1201
  ): number {
1202
+ const values = copySliceValues(src, count)
1065
1203
  if (isComplexSlice(dst)) {
1066
1204
  const dstMeta = dst.__meta__
1067
-
1068
- if (isComplexSlice(src)) {
1069
- const srcMeta = src.__meta__
1070
- for (let i = 0; i < count; i++) {
1071
- dstMeta.backing[dstMeta.offset + i] =
1072
- srcMeta.backing[srcMeta.offset + i]
1073
- ;(dst as any)[i] = srcMeta.backing[srcMeta.offset + i]
1074
- }
1075
- } else if (Array.isArray(src)) {
1076
- for (let i = 0; i < count; i++) {
1077
- dstMeta.backing[dstMeta.offset + i] = src[i]
1078
- ;(dst as any)[i] = src[i]
1079
- }
1205
+ for (let i = 0; i < count; i++) {
1206
+ dstMeta.backing[dstMeta.offset + i] = values[i]
1207
+ ;(dst as any)[i] = values[i]
1080
1208
  }
1081
1209
  } else if (Array.isArray(dst)) {
1082
- if (isComplexSlice(src)) {
1083
- const srcMeta = src.__meta__
1084
- for (let i = 0; i < count; i++) {
1085
- dst[i] = srcMeta.backing[srcMeta.offset + i]
1086
- }
1087
- } else if (Array.isArray(src)) {
1088
- for (let i = 0; i < count; i++) {
1089
- dst[i] = src[i]
1090
- }
1210
+ for (let i = 0; i < count; i++) {
1211
+ dst[i] = values[i]
1091
1212
  }
1092
1213
  }
1093
1214
  return count
1094
1215
  }
1095
1216
 
1217
+ function copySliceValues<T>(src: Slice<T>, count: number): T[] {
1218
+ const values = new Array<T>(count)
1219
+ if (isComplexSlice(src)) {
1220
+ const srcMeta = src.__meta__
1221
+ for (let i = 0; i < count; i++) {
1222
+ values[i] = srcMeta.backing[srcMeta.offset + i]
1223
+ }
1224
+ } else if (Array.isArray(src)) {
1225
+ for (let i = 0; i < count; i++) {
1226
+ values[i] = src[i]
1227
+ }
1228
+ }
1229
+ return values
1230
+ }
1231
+
1096
1232
  /**
1097
1233
  * Accesses an element at a specific index for various Go-like types (string, slice, array).
1098
1234
  * Mimics Go's indexing behavior: `myCollection[index]`
@@ -1105,14 +1241,14 @@ function copyBetweenSlices<T>(
1105
1241
  * @throws Error if index is out of bounds or type is unsupported.
1106
1242
  */
1107
1243
  export function index<T>(
1108
- collection: string | Slice<T> | T[],
1244
+ collection: GoStringValue | Slice<T> | T[],
1109
1245
  index: number,
1110
1246
  ): T | number {
1111
1247
  if (collection === null || collection === undefined) {
1112
1248
  throw new Error('runtime error: index on nil or undefined collection')
1113
1249
  }
1114
1250
 
1115
- if (typeof collection === 'string') {
1251
+ if (isGoStringValue(collection)) {
1116
1252
  return indexString(collection, index) // Use the existing indexString for byte access
1117
1253
  } else if (collection instanceof Uint8Array) {
1118
1254
  if (index < 0 || index >= collection.length) {
@@ -1164,6 +1300,8 @@ export function indexRef<T>(
1164
1300
  },
1165
1301
  __isVarRef: true,
1166
1302
  __goAddress: () => indexAddress(collection, index),
1303
+ __goCollection: collection,
1304
+ __goIndex: index,
1167
1305
  }
1168
1306
  }
1169
1307
  if (isComplexSlice(collection)) {
@@ -1182,6 +1320,8 @@ export function indexRef<T>(
1182
1320
  },
1183
1321
  __isVarRef: true,
1184
1322
  __goAddress: () => indexAddress(collection, index),
1323
+ __goCollection: collection,
1324
+ __goIndex: index,
1185
1325
  }
1186
1326
  }
1187
1327
  if (Array.isArray(collection)) {
@@ -1199,11 +1339,41 @@ export function indexRef<T>(
1199
1339
  },
1200
1340
  __isVarRef: true,
1201
1341
  __goAddress: () => indexAddress(collection, index),
1342
+ __goCollection: collection,
1343
+ __goIndex: index,
1202
1344
  }
1203
1345
  }
1204
1346
  throw new Error('runtime error: index on unsupported type')
1205
1347
  }
1206
1348
 
1349
+ /**
1350
+ * arrayPointerFromIndexRef turns &slice[i] into a pointer to an N-element array
1351
+ * view. This models unsafe conversions such as (*[64]byte)(unsafe.Pointer(&b[0]))
1352
+ * for packages that immediately slice or index the resulting array pointer.
1353
+ */
1354
+ export function arrayPointerFromIndexRef<T>(
1355
+ ref: VarRef<T>,
1356
+ length: number,
1357
+ ): VarRef<Slice<T> | T[] | Uint8Array> {
1358
+ const collection = ref.__goCollection as
1359
+ | Slice<T>
1360
+ | T[]
1361
+ | Uint8Array
1362
+ | undefined
1363
+ if (collection === undefined) {
1364
+ throw new Error(
1365
+ 'unsafe array pointer requires an indexed collection reference',
1366
+ )
1367
+ }
1368
+ const index = ref.__goIndex ?? 0
1369
+ return varRef(
1370
+ goSlice(collection as any, index, index + length) as
1371
+ | Slice<T>
1372
+ | T[]
1373
+ | Uint8Array,
1374
+ )
1375
+ }
1376
+
1207
1377
  /**
1208
1378
  * indexAddress returns a stable synthetic address for an addressable slice or
1209
1379
  * array element.
@@ -1316,10 +1486,10 @@ export const byte = (n: number): number => {
1316
1486
  * @throws Error if index is out of bounds.
1317
1487
  */
1318
1488
  export const indexString = (
1319
- str: string | import('./builtin.js').Bytes,
1489
+ str: GoStringValue | import('./builtin.js').Bytes,
1320
1490
  index: number,
1321
1491
  ): number => {
1322
- if (typeof str !== 'string') {
1492
+ if (!isGoStringValue(str)) {
1323
1493
  // Bytes - access directly
1324
1494
  if (str instanceof Uint8Array) {
1325
1495
  if (index < 0 || index >= str.length) {
@@ -1342,7 +1512,7 @@ export const indexString = (
1342
1512
  }
1343
1513
  return str[index]
1344
1514
  }
1345
- const bytes = new TextEncoder().encode(str)
1515
+ const bytes = goStringBytes(str)
1346
1516
  if (index < 0 || index >= bytes.length) {
1347
1517
  throw new Error(
1348
1518
  `runtime error: index out of range [${index}] with length ${bytes.length}`,
@@ -1357,8 +1527,8 @@ export const indexString = (
1357
1527
  * @param str The string.
1358
1528
  * @returns The number of bytes in the UTF-8 representation of the string.
1359
1529
  */
1360
- export const stringLen = (str: string): number => {
1361
- return new TextEncoder().encode(str).length
1530
+ export const stringLen = (str: GoStringValue): number => {
1531
+ return goStringBytes(str).length
1362
1532
  }
1363
1533
 
1364
1534
  /**
@@ -1371,11 +1541,11 @@ export const stringLen = (str: string): number => {
1371
1541
  * @throws Error if the slice would create invalid UTF-8.
1372
1542
  */
1373
1543
  export const sliceString = (
1374
- str: string,
1544
+ str: GoStringValue,
1375
1545
  low?: number,
1376
1546
  high?: number,
1377
1547
  ): string => {
1378
- const bytes = new TextEncoder().encode(str)
1548
+ const bytes = goStringBytes(str)
1379
1549
  const actualLow = low === undefined ? 0 : low
1380
1550
  const actualHigh = high === undefined ? bytes.length : high
1381
1551
 
@@ -1397,21 +1567,7 @@ export const sliceString = (
1397
1567
  )
1398
1568
  }
1399
1569
 
1400
- const slicedBytes = bytes.subarray(actualLow, actualHigh)
1401
-
1402
- try {
1403
- // Attempt to decode with strict UTF-8 validation
1404
- const result = new TextDecoder('utf-8', { fatal: true }).decode(slicedBytes)
1405
- return result
1406
- } catch (e: unknown) {
1407
- // If we get here, the slice would create invalid UTF-8
1408
- // This is a fundamental limitation of JavaScript string handling
1409
- throw new Error(
1410
- `Cannot slice string at byte indices [${actualLow}:${actualHigh}] because it would create invalid UTF-8. ` +
1411
- `This is a limitation of JavaScript's string handling.`,
1412
- { cause: e },
1413
- )
1414
- }
1570
+ return goStringFromBytes(bytes.subarray(actualLow, actualHigh))
1415
1571
  }
1416
1572
 
1417
1573
  /**
@@ -1425,7 +1581,7 @@ export const bytesToString = (
1425
1581
  if (bytes === null) return ''
1426
1582
  // If it's already a string, just return it
1427
1583
  if (typeof bytes === 'string') return bytes
1428
- if (bytes instanceof Uint8Array) return decodeGoStringBytes(bytes)
1584
+ if (bytes instanceof Uint8Array) return goStringFromBytes(bytes)
1429
1585
  // Ensure we get a plain number[] for Uint8Array.from
1430
1586
  let byteArray: number[]
1431
1587
  if (isComplexSlice(bytes)) {
@@ -1438,15 +1594,105 @@ export const bytesToString = (
1438
1594
  // For simple T[] slices
1439
1595
  byteArray = bytes
1440
1596
  }
1441
- return decodeGoStringBytes(Uint8Array.from(byteArray))
1597
+ return goStringFromBytes(Uint8Array.from(byteArray)) as string
1442
1598
  }
1443
1599
 
1444
- function decodeGoStringBytes(bytes: Uint8Array): string {
1445
- try {
1446
- return new TextDecoder('utf-8', { fatal: true }).decode(bytes)
1447
- } catch {
1448
- return bytesToBinaryString(bytes)
1600
+ export function stringEqual(
1601
+ left: GoStringBytes,
1602
+ right: GoStringBytes,
1603
+ ): boolean {
1604
+ const leftBytes = goStringComparableBytes(left)
1605
+ const rightBytes = goStringComparableBytes(right)
1606
+ if (leftBytes.length !== rightBytes.length) {
1607
+ return false
1608
+ }
1609
+ for (let i = 0; i < leftBytes.length; i++) {
1610
+ if (leftBytes[i] !== rightBytes[i]) {
1611
+ return false
1612
+ }
1613
+ }
1614
+ return true
1615
+ }
1616
+
1617
+ export function stringCompare(
1618
+ left: GoStringBytes,
1619
+ right: GoStringBytes,
1620
+ ): number {
1621
+ if (!isGoStringValue(left) && !isGoStringValue(right)) {
1622
+ const leftBytes = byteStringView(left)
1623
+ const rightBytes = byteStringView(right)
1624
+ const leftLen = leftBytes.length
1625
+ const rightLen = rightBytes.length
1626
+ const sharedLen = Math.min(leftLen, rightLen)
1627
+ for (let i = 0; i < sharedLen; i++) {
1628
+ const diff =
1629
+ (leftBytes.backing[leftBytes.offset + i] ?? 0) -
1630
+ (rightBytes.backing[rightBytes.offset + i] ?? 0)
1631
+ if (diff !== 0) {
1632
+ return diff
1633
+ }
1634
+ }
1635
+ return leftLen - rightLen
1636
+ }
1637
+
1638
+ const leftBytes = goStringComparableBytes(left)
1639
+ const rightBytes = goStringComparableBytes(right)
1640
+ const sharedLen = Math.min(leftBytes.length, rightBytes.length)
1641
+ for (let i = 0; i < sharedLen; i++) {
1642
+ const diff = leftBytes[i] - rightBytes[i]
1643
+ if (diff !== 0) {
1644
+ return diff
1645
+ }
1449
1646
  }
1647
+ return leftBytes.length - rightBytes.length
1648
+ }
1649
+
1650
+ type ByteStringView = {
1651
+ backing: ArrayLike<number>
1652
+ offset: number
1653
+ length: number
1654
+ }
1655
+
1656
+ function byteStringView(value: GoStringBytes): ByteStringView {
1657
+ value = collectionValue(value) as GoStringBytes
1658
+ if (value === null || value === undefined) {
1659
+ return { backing: [], offset: 0, length: 0 }
1660
+ }
1661
+ if (value instanceof Uint8Array) {
1662
+ return { backing: value, offset: 0, length: value.length }
1663
+ }
1664
+ if (Array.isArray(value)) {
1665
+ const meta = (value as unknown as SliceProxy<number>).__meta__
1666
+ if (meta !== undefined) {
1667
+ return {
1668
+ backing: meta.backing,
1669
+ offset: meta.offset,
1670
+ length: meta.length,
1671
+ }
1672
+ }
1673
+ return { backing: value, offset: 0, length: value.length }
1674
+ }
1675
+ const meta = (value as unknown as SliceProxy<number>).__meta__
1676
+ return {
1677
+ backing: meta.backing,
1678
+ offset: meta.offset,
1679
+ length: meta.length,
1680
+ }
1681
+ }
1682
+
1683
+ function collectionValue(value: unknown): unknown {
1684
+ if (isVarRef(value)) {
1685
+ return collectionValue(value.value)
1686
+ }
1687
+ if (
1688
+ typeof value === 'object' &&
1689
+ value !== null &&
1690
+ typeof (value as { __goType?: unknown }).__goType === 'string' &&
1691
+ '__goValue' in value
1692
+ ) {
1693
+ return collectionValue((value as { __goValue: unknown }).__goValue)
1694
+ }
1695
+ return value
1450
1696
  }
1451
1697
 
1452
1698
  function bytesToBinaryString(bytes: Uint8Array): string {
@@ -1464,10 +1710,10 @@ function bytesToBinaryString(bytes: Uint8Array): string {
1464
1710
  * @returns A Uint8Array representing the UTF-8 bytes of the string.
1465
1711
  */
1466
1712
  export function stringToBytes(
1467
- s: string | import('./builtin.js').Bytes,
1713
+ s: GoStringValue | import('./builtin.js').Bytes,
1468
1714
  ): Uint8Array {
1469
- if (typeof s === 'string') {
1470
- return new TextEncoder().encode(s)
1715
+ if (isGoStringValue(s)) {
1716
+ return goStringBytes(s)
1471
1717
  }
1472
1718
  // Already bytes - normalize to Uint8Array
1473
1719
  if (s instanceof Uint8Array) {
@@ -1480,6 +1726,71 @@ export function stringToBytes(
1480
1726
  return new Uint8Array(Array.isArray(s) ? s : [])
1481
1727
  }
1482
1728
 
1729
+ type StringHeaderData = {
1730
+ kind: 'string'
1731
+ value: string
1732
+ }
1733
+
1734
+ export function stringHeaderRef(s: VarRef<string>): VarRef<{
1735
+ Data: StringHeaderData
1736
+ Len: number
1737
+ }> {
1738
+ return varRef({
1739
+ get Data(): StringHeaderData {
1740
+ return { kind: 'string', value: s.value }
1741
+ },
1742
+ set Data(_value: StringHeaderData) {},
1743
+ get Len(): number {
1744
+ return stringToBytes(s.value).length
1745
+ },
1746
+ set Len(_value: number) {},
1747
+ })
1748
+ }
1749
+
1750
+ export function sliceHeaderRef(b: VarRef<Slice<number>>): VarRef<{
1751
+ Data: StringHeaderData | null
1752
+ Len: number
1753
+ Cap: number
1754
+ }> {
1755
+ let data: StringHeaderData | null = null
1756
+ let length = 0
1757
+ let capacity = 0
1758
+ const refresh = () => {
1759
+ if (data === null) {
1760
+ return
1761
+ }
1762
+ const bytes = stringToBytes(data.value)
1763
+ const out = makeSlice<number>(length, Math.max(capacity, length), 'byte')
1764
+ if (out !== null) {
1765
+ copy(out, goSlice(bytes, 0, Math.min(length, bytes.length)))
1766
+ }
1767
+ b.value = out
1768
+ }
1769
+ return varRef({
1770
+ get Data(): StringHeaderData | null {
1771
+ return data
1772
+ },
1773
+ set Data(value: StringHeaderData | null) {
1774
+ data = value
1775
+ refresh()
1776
+ },
1777
+ get Len(): number {
1778
+ return length
1779
+ },
1780
+ set Len(value: number) {
1781
+ length = value
1782
+ refresh()
1783
+ },
1784
+ get Cap(): number {
1785
+ return capacity
1786
+ },
1787
+ set Cap(value: number) {
1788
+ capacity = value
1789
+ refresh()
1790
+ },
1791
+ })
1792
+ }
1793
+
1483
1794
  /**
1484
1795
  * Handles string() conversion for values that could be either string or []byte.
1485
1796
  * Used for generic type parameters with constraint []byte|string.
@@ -1492,8 +1803,8 @@ export function genericBytesOrStringToString(
1492
1803
  if (value === null || value === undefined) {
1493
1804
  return ''
1494
1805
  }
1495
- if (typeof value === 'string') {
1496
- return value
1806
+ if (isGoStringValue(value)) {
1807
+ return value as string
1497
1808
  }
1498
1809
  return bytesToString(value)
1499
1810
  }
@@ -1507,10 +1818,10 @@ export function genericBytesOrStringToString(
1507
1818
  * @returns The byte value at the specified index
1508
1819
  */
1509
1820
  export function indexStringOrBytes(
1510
- value: string | import('./builtin.js').Bytes,
1821
+ value: GoStringValue | import('./builtin.js').Bytes,
1511
1822
  index: number,
1512
1823
  ): number {
1513
- if (typeof value === 'string') {
1824
+ if (isGoStringValue(value)) {
1514
1825
  return indexString(value, index)
1515
1826
  } else if (value instanceof Uint8Array) {
1516
1827
  // For Uint8Array, direct access returns the byte value
@@ -1546,9 +1857,9 @@ export function indexStringOrBytes(
1546
1857
  * @returns The sliced value of the same type as input
1547
1858
  */
1548
1859
  export function sliceStringOrBytes<
1549
- T extends string | import('./builtin.js').Bytes,
1860
+ T extends GoStringValue | import('./builtin.js').Bytes,
1550
1861
  >(value: T, low?: number, high?: number, max?: number): T {
1551
- if (typeof value === 'string') {
1862
+ if (isGoStringValue(value)) {
1552
1863
  // For strings, use sliceString and ignore max parameter
1553
1864
  return sliceString(value, low, high) as T
1554
1865
  } else {