goscript 0.1.3 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (330) hide show
  1. package/README.md +5 -2
  2. package/cmd/go_js_wasm_exec/main.go +201 -0
  3. package/cmd/go_js_wasm_exec/main_test.go +83 -0
  4. package/cmd/goscript/{cmd_compile.go → cmd-compile.go} +35 -8
  5. package/cmd/goscript/cmd-test.go +14 -0
  6. package/cmd/goscript/cmd-test_test.go +1 -1
  7. package/cmd/goscript/cmd_compile_test.go +105 -6
  8. package/compiler/build-flags.go +9 -10
  9. package/compiler/compile-request.go +12 -9
  10. package/compiler/compliance_test.go +0 -1
  11. package/compiler/config.go +2 -0
  12. package/compiler/gotest/request.go +28 -0
  13. package/compiler/gotest/runner.go +353 -27
  14. package/compiler/gotest/runner_test.go +400 -1
  15. package/compiler/gotest/testdata/browserapi/browserapi_test.go +20 -0
  16. package/compiler/gotest/testdata/browserapi/go.mod +3 -0
  17. package/compiler/lowered-program.go +24 -17
  18. package/compiler/lowering.go +988 -263
  19. package/compiler/lowering_bench_test.go +364 -0
  20. package/compiler/override-facts.go +15 -0
  21. package/compiler/override-parity-verifier.go +450 -0
  22. package/compiler/override-parity.go +122 -0
  23. package/compiler/override-registry_test.go +559 -0
  24. package/compiler/package-graph.go +61 -4
  25. package/compiler/package-graph_test.go +30 -0
  26. package/compiler/protobuf-ts-binding.go +514 -0
  27. package/compiler/protobuf-ts-binding_test.go +172 -0
  28. package/compiler/semantic-model-types.go +17 -4
  29. package/compiler/semantic-model.go +709 -72
  30. package/compiler/semantic-model_test.go +219 -0
  31. package/compiler/service.go +20 -1
  32. package/compiler/skeleton_test.go +1008 -20
  33. package/compiler/typescript-emitter.go +147 -15
  34. package/dist/gs/builtin/builtin.d.ts +2 -2
  35. package/dist/gs/builtin/builtin.js +20 -0
  36. package/dist/gs/builtin/builtin.js.map +1 -1
  37. package/dist/gs/builtin/slice.d.ts +2 -1
  38. package/dist/gs/builtin/slice.js +34 -4
  39. package/dist/gs/builtin/slice.js.map +1 -1
  40. package/dist/gs/builtin/type.d.ts +14 -6
  41. package/dist/gs/builtin/type.js +224 -64
  42. package/dist/gs/builtin/type.js.map +1 -1
  43. package/dist/gs/builtin/varRef.d.ts +11 -0
  44. package/dist/gs/builtin/varRef.js +57 -2
  45. package/dist/gs/builtin/varRef.js.map +1 -1
  46. package/dist/gs/bytes/buffer.gs.js +1 -1
  47. package/dist/gs/bytes/buffer.gs.js.map +1 -1
  48. package/dist/gs/bytes/reader.gs.js +1 -1
  49. package/dist/gs/bytes/reader.gs.js.map +1 -1
  50. package/dist/gs/compress/zlib/index.d.ts +13 -6
  51. package/dist/gs/compress/zlib/index.js +131 -35
  52. package/dist/gs/compress/zlib/index.js.map +1 -1
  53. package/dist/gs/crypto/sha1/index.js +2 -5
  54. package/dist/gs/crypto/sha1/index.js.map +1 -1
  55. package/dist/gs/crypto/sha256/index.js +2 -5
  56. package/dist/gs/crypto/sha256/index.js.map +1 -1
  57. package/dist/gs/crypto/sha512/index.js +2 -5
  58. package/dist/gs/crypto/sha512/index.js.map +1 -1
  59. package/dist/gs/embed/index.d.ts +6 -0
  60. package/dist/gs/embed/index.js +210 -5
  61. package/dist/gs/embed/index.js.map +1 -1
  62. package/dist/gs/encoding/json/index.d.ts +114 -0
  63. package/dist/gs/encoding/json/index.js +544 -36
  64. package/dist/gs/encoding/json/index.js.map +1 -1
  65. package/dist/gs/fmt/fmt.d.ts +3 -3
  66. package/dist/gs/fmt/fmt.js +29 -16
  67. package/dist/gs/fmt/fmt.js.map +1 -1
  68. package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.d.ts +100 -0
  69. package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.js +564 -0
  70. package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.js.map +1 -1
  71. package/dist/gs/github.com/go-git/go-billy/v6/osfs/index.d.ts +45 -0
  72. package/dist/gs/github.com/go-git/go-billy/v6/osfs/index.js +229 -0
  73. package/dist/gs/github.com/go-git/go-billy/v6/osfs/index.js.map +1 -0
  74. package/dist/gs/github.com/pkg/errors/errors.js +54 -30
  75. package/dist/gs/github.com/pkg/errors/errors.js.map +1 -1
  76. package/dist/gs/go/scanner/index.d.ts +2 -0
  77. package/dist/gs/go/scanner/index.js +29 -5
  78. package/dist/gs/go/scanner/index.js.map +1 -1
  79. package/dist/gs/go/token/index.js +22 -6
  80. package/dist/gs/go/token/index.js.map +1 -1
  81. package/dist/gs/hash/index.d.ts +6 -0
  82. package/dist/gs/hash/index.js +20 -0
  83. package/dist/gs/hash/index.js.map +1 -1
  84. package/dist/gs/internal/goarch/index.d.ts +43 -3
  85. package/dist/gs/internal/goarch/index.js +42 -10
  86. package/dist/gs/internal/goarch/index.js.map +1 -1
  87. package/dist/gs/io/fs/fs.js +26 -14
  88. package/dist/gs/io/fs/fs.js.map +1 -1
  89. package/dist/gs/io/fs/readdir.js +8 -4
  90. package/dist/gs/io/fs/readdir.js.map +1 -1
  91. package/dist/gs/io/fs/sub.js +8 -1
  92. package/dist/gs/io/fs/sub.js.map +1 -1
  93. package/dist/gs/io/io.d.ts +12 -6
  94. package/dist/gs/io/io.js +87 -42
  95. package/dist/gs/io/io.js.map +1 -1
  96. package/dist/gs/math/bits/index.d.ts +31 -5
  97. package/dist/gs/math/bits/index.js +29 -28
  98. package/dist/gs/math/bits/index.js.map +1 -1
  99. package/dist/gs/mime/index.d.ts +16 -0
  100. package/dist/gs/mime/index.js +315 -6
  101. package/dist/gs/mime/index.js.map +1 -1
  102. package/dist/gs/net/http/httptest/index.d.ts +12 -0
  103. package/dist/gs/net/http/httptest/index.js +85 -6
  104. package/dist/gs/net/http/httptest/index.js.map +1 -1
  105. package/dist/gs/net/http/index.d.ts +303 -6
  106. package/dist/gs/net/http/index.js +1615 -58
  107. package/dist/gs/net/http/index.js.map +1 -1
  108. package/dist/gs/os/dir_unix.gs.js +1 -1
  109. package/dist/gs/os/dir_unix.gs.js.map +1 -1
  110. package/dist/gs/os/error.gs.js +1 -1
  111. package/dist/gs/os/error.gs.js.map +1 -1
  112. package/dist/gs/os/exec.gs.d.ts +1 -0
  113. package/dist/gs/os/exec.gs.js +4 -8
  114. package/dist/gs/os/exec.gs.js.map +1 -1
  115. package/dist/gs/os/exec_posix.gs.js +1 -1
  116. package/dist/gs/os/exec_posix.gs.js.map +1 -1
  117. package/dist/gs/os/index.d.ts +1 -1
  118. package/dist/gs/os/index.js +1 -1
  119. package/dist/gs/os/index.js.map +1 -1
  120. package/dist/gs/os/proc.gs.d.ts +4 -0
  121. package/dist/gs/os/proc.gs.js +12 -6
  122. package/dist/gs/os/proc.gs.js.map +1 -1
  123. package/dist/gs/os/root_js.gs.js +1 -1
  124. package/dist/gs/os/root_js.gs.js.map +1 -1
  125. package/dist/gs/os/types.gs.js +1 -1
  126. package/dist/gs/os/types.gs.js.map +1 -1
  127. package/dist/gs/os/types_js.gs.d.ts +6 -2
  128. package/dist/gs/os/types_js.gs.js +170 -9
  129. package/dist/gs/os/types_js.gs.js.map +1 -1
  130. package/dist/gs/os/types_unix.gs.js +1 -1
  131. package/dist/gs/os/types_unix.gs.js.map +1 -1
  132. package/dist/gs/path/path.js +11 -7
  133. package/dist/gs/path/path.js.map +1 -1
  134. package/dist/gs/reflect/index.d.ts +5 -4
  135. package/dist/gs/reflect/index.js +4 -3
  136. package/dist/gs/reflect/index.js.map +1 -1
  137. package/dist/gs/reflect/map.js +15 -0
  138. package/dist/gs/reflect/map.js.map +1 -1
  139. package/dist/gs/reflect/type.d.ts +26 -6
  140. package/dist/gs/reflect/type.js +1498 -279
  141. package/dist/gs/reflect/type.js.map +1 -1
  142. package/dist/gs/reflect/types.d.ts +14 -6
  143. package/dist/gs/reflect/types.js +35 -1
  144. package/dist/gs/reflect/types.js.map +1 -1
  145. package/dist/gs/reflect/value.d.ts +1 -0
  146. package/dist/gs/reflect/value.js +83 -41
  147. package/dist/gs/reflect/value.js.map +1 -1
  148. package/dist/gs/reflect/visiblefields.js +4 -140
  149. package/dist/gs/reflect/visiblefields.js.map +1 -1
  150. package/dist/gs/runtime/pprof/index.d.ts +8 -2
  151. package/dist/gs/runtime/pprof/index.js +50 -30
  152. package/dist/gs/runtime/pprof/index.js.map +1 -1
  153. package/dist/gs/runtime/runtime.js +5 -4
  154. package/dist/gs/runtime/runtime.js.map +1 -1
  155. package/dist/gs/runtime/trace/index.js +5 -19
  156. package/dist/gs/runtime/trace/index.js.map +1 -1
  157. package/dist/gs/strconv/atoi.gs.js +1 -1
  158. package/dist/gs/strconv/atoi.gs.js.map +1 -1
  159. package/dist/gs/strconv/complex.gs.d.ts +3 -0
  160. package/dist/gs/strconv/complex.gs.js +148 -0
  161. package/dist/gs/strconv/complex.gs.js.map +1 -0
  162. package/dist/gs/strconv/index.d.ts +1 -0
  163. package/dist/gs/strconv/index.js +1 -0
  164. package/dist/gs/strconv/index.js.map +1 -1
  165. package/dist/gs/strings/builder.js +1 -1
  166. package/dist/gs/strings/reader.d.ts +1 -1
  167. package/dist/gs/strings/reader.js +11 -7
  168. package/dist/gs/strings/reader.js.map +1 -1
  169. package/dist/gs/strings/replace.js +15 -7
  170. package/dist/gs/strings/replace.js.map +1 -1
  171. package/dist/gs/strings/strings.d.ts +5 -0
  172. package/dist/gs/strings/strings.js +57 -5
  173. package/dist/gs/strings/strings.js.map +1 -1
  174. package/dist/gs/sync/atomic/type.gs.js +9 -9
  175. package/dist/gs/sync/atomic/type.gs.js.map +1 -1
  176. package/dist/gs/sync/atomic/value.gs.js +2 -2
  177. package/dist/gs/sync/atomic/value.gs.js.map +1 -1
  178. package/dist/gs/sync/sync.d.ts +2 -1
  179. package/dist/gs/sync/sync.js +37 -16
  180. package/dist/gs/sync/sync.js.map +1 -1
  181. package/dist/gs/syscall/env.js +22 -14
  182. package/dist/gs/syscall/env.js.map +1 -1
  183. package/dist/gs/syscall/js/index.js +9 -0
  184. package/dist/gs/syscall/js/index.js.map +1 -1
  185. package/dist/gs/testing/testing.js +59 -15
  186. package/dist/gs/testing/testing.js.map +1 -1
  187. package/dist/gs/time/time.d.ts +24 -1
  188. package/dist/gs/time/time.js +43 -3
  189. package/dist/gs/time/time.js.map +1 -1
  190. package/dist/gs/unique/index.js +7 -1
  191. package/dist/gs/unique/index.js.map +1 -1
  192. package/go.mod +3 -3
  193. package/go.sum +16 -0
  194. package/gs/builtin/builtin.ts +25 -2
  195. package/gs/builtin/runtime-contract.test.ts +260 -18
  196. package/gs/builtin/slice.ts +51 -4
  197. package/gs/builtin/type.ts +310 -63
  198. package/gs/builtin/varRef.ts +85 -2
  199. package/gs/bytes/buffer.gs.ts +1 -1
  200. package/gs/bytes/reader.gs.ts +1 -1
  201. package/gs/compress/zlib/index.test.ts +159 -1
  202. package/gs/compress/zlib/index.ts +164 -37
  203. package/gs/compress/zlib/meta.json +4 -1
  204. package/gs/compress/zlib/parity.json +51 -0
  205. package/gs/crypto/sha1/index.test.ts +19 -2
  206. package/gs/crypto/sha1/index.ts +3 -6
  207. package/gs/crypto/sha256/index.test.ts +14 -2
  208. package/gs/crypto/sha256/index.ts +3 -6
  209. package/gs/crypto/sha512/index.test.ts +17 -2
  210. package/gs/crypto/sha512/index.ts +3 -6
  211. package/gs/embed/index.test.ts +87 -0
  212. package/gs/embed/index.ts +229 -5
  213. package/gs/encoding/json/index.test.ts +360 -6
  214. package/gs/encoding/json/index.ts +679 -38
  215. package/gs/encoding/json/parity.json +81 -0
  216. package/gs/fmt/fmt.test.ts +41 -3
  217. package/gs/fmt/fmt.ts +40 -17
  218. package/gs/fmt/meta.json +6 -1
  219. package/gs/github.com/aperturerobotics/protobuf-go-lite/index.test.ts +211 -3
  220. package/gs/github.com/aperturerobotics/protobuf-go-lite/index.ts +857 -1
  221. package/gs/github.com/go-git/go-billy/v6/osfs/index.test.ts +110 -0
  222. package/gs/github.com/go-git/go-billy/v6/osfs/index.ts +280 -0
  223. package/gs/github.com/go-git/go-billy/v6/osfs/meta.json +8 -0
  224. package/gs/github.com/pkg/errors/errors.ts +54 -30
  225. package/gs/go/scanner/index.test.ts +39 -56
  226. package/gs/go/scanner/index.ts +33 -5
  227. package/gs/go/scanner/parity.json +27 -0
  228. package/gs/go/token/index.ts +22 -6
  229. package/gs/hash/index.test.ts +20 -33
  230. package/gs/hash/index.ts +28 -0
  231. package/gs/hash/parity.json +21 -0
  232. package/gs/internal/goarch/index.test.ts +32 -0
  233. package/gs/internal/goarch/index.ts +45 -13
  234. package/gs/internal/goarch/parity.json +144 -0
  235. package/gs/io/fs/fs.ts +26 -14
  236. package/gs/io/fs/readdir.test.ts +38 -0
  237. package/gs/io/fs/readdir.ts +8 -4
  238. package/gs/io/fs/sub.ts +8 -1
  239. package/gs/io/io.test.ts +77 -6
  240. package/gs/io/io.ts +115 -52
  241. package/gs/io/meta.json +7 -1
  242. package/gs/io/parity.json +162 -0
  243. package/gs/math/bits/index.test.ts +14 -1
  244. package/gs/math/bits/index.ts +75 -32
  245. package/gs/math/bits/parity.json +156 -0
  246. package/gs/mime/index.test.ts +90 -0
  247. package/gs/mime/index.ts +369 -6
  248. package/gs/mime/parity.json +36 -0
  249. package/gs/net/http/httptest/index.test.ts +98 -2
  250. package/gs/net/http/httptest/index.ts +101 -6
  251. package/gs/net/http/httptest/parity.json +15 -0
  252. package/gs/net/http/index.test.ts +797 -12
  253. package/gs/net/http/index.ts +1874 -136
  254. package/gs/net/http/meta.json +16 -1
  255. package/gs/net/http/parity.json +193 -0
  256. package/gs/os/dir_unix.gs.ts +1 -1
  257. package/gs/os/error.gs.ts +1 -1
  258. package/gs/os/exec.gs.ts +4 -8
  259. package/gs/os/exec_posix.gs.ts +1 -1
  260. package/gs/os/file_unix_js.test.ts +52 -0
  261. package/gs/os/index.test.ts +9 -0
  262. package/gs/os/index.ts +1 -0
  263. package/gs/os/meta.json +4 -0
  264. package/gs/os/parity.json +9 -0
  265. package/gs/os/proc.gs.ts +18 -5
  266. package/gs/os/proc.test.ts +26 -0
  267. package/gs/os/readdir.test.ts +56 -0
  268. package/gs/os/root_js.gs.ts +1 -1
  269. package/gs/os/types.gs.ts +1 -1
  270. package/gs/os/types_js.gs.ts +170 -9
  271. package/gs/os/types_unix.gs.ts +1 -1
  272. package/gs/path/path.ts +11 -7
  273. package/gs/reflect/deepequal.test.ts +10 -1
  274. package/gs/reflect/field.test.ts +37 -15
  275. package/gs/reflect/function-types.test.ts +518 -22
  276. package/gs/reflect/index.ts +8 -6
  277. package/gs/reflect/map.ts +20 -0
  278. package/gs/reflect/meta.json +6 -4
  279. package/gs/reflect/parity.json +234 -0
  280. package/gs/reflect/sliceat.test.ts +156 -0
  281. package/gs/reflect/structof.test.ts +401 -0
  282. package/gs/reflect/type.ts +1980 -365
  283. package/gs/reflect/typefor.test.ts +540 -10
  284. package/gs/reflect/types.ts +43 -18
  285. package/gs/reflect/value.ts +105 -45
  286. package/gs/reflect/visiblefields.ts +5 -168
  287. package/gs/runtime/parity.json +24 -0
  288. package/gs/runtime/pprof/index.test.ts +29 -7
  289. package/gs/runtime/pprof/index.ts +56 -30
  290. package/gs/runtime/pprof/parity.json +27 -0
  291. package/gs/runtime/runtime.test.ts +3 -1
  292. package/gs/runtime/runtime.ts +4 -3
  293. package/gs/runtime/trace/index.test.ts +5 -3
  294. package/gs/runtime/trace/index.ts +8 -20
  295. package/gs/runtime/trace/parity.json +36 -0
  296. package/gs/strconv/atoi.gs.ts +1 -1
  297. package/gs/strconv/complex.gs.ts +174 -0
  298. package/gs/strconv/complex.test.ts +65 -0
  299. package/gs/strconv/index.ts +1 -0
  300. package/gs/strconv/parity.json +120 -0
  301. package/gs/strings/builder.ts +1 -1
  302. package/gs/strings/meta.json +5 -2
  303. package/gs/strings/parity.json +186 -0
  304. package/gs/strings/reader.test.ts +2 -2
  305. package/gs/strings/reader.ts +11 -7
  306. package/gs/strings/replace.ts +15 -7
  307. package/gs/strings/strings.test.ts +22 -2
  308. package/gs/strings/strings.ts +64 -6
  309. package/gs/sync/atomic/type.gs.ts +9 -9
  310. package/gs/sync/atomic/value.gs.ts +2 -2
  311. package/gs/sync/meta.json +1 -0
  312. package/gs/sync/sync.test.ts +41 -1
  313. package/gs/sync/sync.ts +41 -16
  314. package/gs/syscall/env.ts +29 -14
  315. package/gs/syscall/js/index.test.ts +18 -0
  316. package/gs/syscall/js/index.ts +12 -0
  317. package/gs/testing/testing.test.ts +99 -3
  318. package/gs/testing/testing.ts +95 -24
  319. package/gs/time/parity.json +225 -0
  320. package/gs/time/time.test.ts +20 -2
  321. package/gs/time/time.ts +49 -7
  322. package/gs/unique/index.ts +7 -1
  323. package/package.json +4 -2
  324. package/dist/gs/github.com/aperturerobotics/starpc/srpc/index.d.ts +0 -217
  325. package/dist/gs/github.com/aperturerobotics/starpc/srpc/index.js +0 -814
  326. package/dist/gs/github.com/aperturerobotics/starpc/srpc/index.js.map +0 -1
  327. package/gs/github.com/aperturerobotics/starpc/srpc/index.test.ts +0 -31
  328. package/gs/github.com/aperturerobotics/starpc/srpc/index.ts +0 -1233
  329. package/gs/github.com/aperturerobotics/starpc/srpc/meta.json +0 -46
  330. /package/compiler/{wasm_api.go → wasm-api.go} +0 -0
@@ -1,3 +1,10 @@
1
+ export interface OwnedPointerHandle<T = unknown> {
2
+ readonly __goOwnedPointer: true
3
+ __goAddress: () => number
4
+ __goRef: () => VarRef<T>
5
+ __goSlice?: (length: number) => unknown
6
+ }
7
+
1
8
  /**
2
9
  * VarRef represents a Go variable which can be referred to by other variables.
3
10
  *
@@ -12,6 +19,51 @@ export type VarRef<T> = {
12
19
  __goAddress?: () => number
13
20
  __goCollection?: unknown
14
21
  __goIndex?: number
22
+ __goPointer?: OwnedPointerHandle<T>
23
+ }
24
+
25
+ const pointerAddressStride = 0x100000000
26
+ const pointerAddresses = new WeakMap<object, number>()
27
+ const fieldPointerAddresses = new WeakMap<
28
+ object,
29
+ globalThis.Map<PropertyKey, number>
30
+ >()
31
+ let nextPointerAddress = 1
32
+
33
+ function pointerAddress(value: object): number {
34
+ let address = pointerAddresses.get(value)
35
+ if (address === undefined) {
36
+ address = nextPointerAddress * pointerAddressStride
37
+ nextPointerAddress++
38
+ pointerAddresses.set(value, address)
39
+ }
40
+ return address
41
+ }
42
+
43
+ function fieldPointerAddress(target: object, key: PropertyKey): number {
44
+ let addresses = fieldPointerAddresses.get(target)
45
+ if (addresses === undefined) {
46
+ addresses = new globalThis.Map<PropertyKey, number>()
47
+ fieldPointerAddresses.set(target, addresses)
48
+ }
49
+ let address = addresses.get(key)
50
+ if (address === undefined) {
51
+ address = nextPointerAddress * pointerAddressStride
52
+ nextPointerAddress++
53
+ addresses.set(key, address)
54
+ }
55
+ return address
56
+ }
57
+
58
+ function refPointer<T>(
59
+ ref: VarRef<T>,
60
+ address: () => number,
61
+ ): OwnedPointerHandle<T> {
62
+ return {
63
+ __goOwnedPointer: true,
64
+ __goAddress: address,
65
+ __goRef: () => ref,
66
+ }
15
67
  }
16
68
 
17
69
  /** Wrap a non-null T in a variable reference. */
@@ -19,7 +71,10 @@ export function varRef<T>(v: T): VarRef<T> {
19
71
  // We create a new object wrapper for every varRef call to ensure
20
72
  // distinct pointer identity, crucial for pointer comparisons (p1 == p2).
21
73
  // The __isVarRef marker allows the reflect system to identify this as a pointer type.
22
- return { value: v, __isVarRef: true }
74
+ const ref: VarRef<T> = { value: v, __isVarRef: true }
75
+ ref.__goAddress = () => pointerAddress(ref)
76
+ ref.__goPointer = refPointer(ref, ref.__goAddress)
77
+ return ref
23
78
  }
24
79
 
25
80
  /** Create a variable reference to an object field. */
@@ -27,7 +82,8 @@ export function fieldRef<T extends object, K extends keyof T>(
27
82
  target: T,
28
83
  key: K,
29
84
  ): VarRef<T[K]> {
30
- return {
85
+ const address = () => fieldPointerAddress(target, key)
86
+ const ref: VarRef<T[K]> = {
31
87
  get value(): T[K] {
32
88
  return target[key]
33
89
  },
@@ -35,7 +91,10 @@ export function fieldRef<T extends object, K extends keyof T>(
35
91
  target[key] = value
36
92
  },
37
93
  __isVarRef: true,
94
+ __goAddress: address,
38
95
  }
96
+ ref.__goPointer = refPointer(ref, address)
97
+ return ref
39
98
  }
40
99
 
41
100
  /** Check if a value is a VarRef (pointer) */
@@ -43,6 +102,30 @@ export function isVarRef(v: unknown): v is VarRef<unknown> {
43
102
  return v !== null && typeof v === 'object' && (v as any).__isVarRef === true
44
103
  }
45
104
 
105
+ export function isOwnedPointerHandle(
106
+ value: unknown,
107
+ ): value is OwnedPointerHandle {
108
+ return (
109
+ value !== null &&
110
+ typeof value === 'object' &&
111
+ (value as { __goOwnedPointer?: unknown }).__goOwnedPointer === true
112
+ )
113
+ }
114
+
115
+ export function ownedPointerFromRef<T>(
116
+ ref: VarRef<T>,
117
+ ): OwnedPointerHandle<T> | undefined {
118
+ return ref.__goPointer
119
+ }
120
+
121
+ export function ownedPointerAddress(pointer: OwnedPointerHandle): number {
122
+ return pointer.__goAddress()
123
+ }
124
+
125
+ export function ownedPointerRef<T>(pointer: OwnedPointerHandle<T>): VarRef<T> {
126
+ return pointer.__goRef()
127
+ }
128
+
46
129
  /** Dereference a variable reference, throws on null → simulates Go panic. */
47
130
  export function unref<T>(b: VarRef<T>): T {
48
131
  if (b === null) {
@@ -549,7 +549,7 @@ export class Buffer {
549
549
  new Buffer(),
550
550
  [{ name: "Bytes", args: [], returns: [{ type: { kind: $.TypeKind.Slice, elemType: { kind: $.TypeKind.Basic, name: "number" } } }] }, { name: "AvailableBuffer", args: [], returns: [{ type: { kind: $.TypeKind.Slice, elemType: { kind: $.TypeKind.Basic, name: "number" } } }] }, { name: "String", args: [], returns: [{ type: { kind: $.TypeKind.Basic, name: "string" } }] }, { name: "empty", args: [], returns: [{ type: { kind: $.TypeKind.Basic, name: "boolean" } }] }, { name: "Len", args: [], returns: [{ type: { kind: $.TypeKind.Basic, name: "number" } }] }, { name: "Cap", args: [], returns: [{ type: { kind: $.TypeKind.Basic, name: "number" } }] }, { name: "Available", args: [], returns: [{ type: { kind: $.TypeKind.Basic, name: "number" } }] }, { name: "Truncate", args: [{ name: "n", type: { kind: $.TypeKind.Basic, name: "number" } }], returns: [] }, { name: "Reset", args: [], returns: [] }, { name: "tryGrowByReslice", args: [{ name: "n", type: { kind: $.TypeKind.Basic, name: "number" } }], returns: [{ type: { kind: $.TypeKind.Basic, name: "number" } }, { type: { kind: $.TypeKind.Basic, name: "boolean" } }] }, { name: "grow", args: [{ name: "n", type: { kind: $.TypeKind.Basic, name: "number" } }], returns: [{ type: { kind: $.TypeKind.Basic, name: "number" } }] }, { name: "Grow", args: [{ name: "n", type: { kind: $.TypeKind.Basic, name: "number" } }], returns: [] }, { name: "Write", args: [{ name: "p", type: { kind: $.TypeKind.Slice, elemType: { kind: $.TypeKind.Basic, name: "number" } } }], returns: [{ type: { kind: $.TypeKind.Basic, name: "number" } }, { type: { kind: $.TypeKind.Interface, name: 'GoError', methods: [{ name: 'Error', args: [], returns: [{ type: { kind: $.TypeKind.Basic, name: 'string' } }] }] } }] }, { name: "WriteString", args: [{ name: "s", type: { kind: $.TypeKind.Basic, name: "string" } }], returns: [{ type: { kind: $.TypeKind.Basic, name: "number" } }, { type: { kind: $.TypeKind.Interface, name: 'GoError', methods: [{ name: 'Error', args: [], returns: [{ type: { kind: $.TypeKind.Basic, name: 'string' } }] }] } }] }, { name: "ReadFrom", args: [{ name: "r", type: "Reader" }], returns: [{ type: { kind: $.TypeKind.Basic, name: "number" } }, { type: { kind: $.TypeKind.Interface, name: 'GoError', methods: [{ name: 'Error', args: [], returns: [{ type: { kind: $.TypeKind.Basic, name: 'string' } }] }] } }] }, { name: "WriteTo", args: [{ name: "w", type: "Writer" }], returns: [{ type: { kind: $.TypeKind.Basic, name: "number" } }, { type: { kind: $.TypeKind.Interface, name: 'GoError', methods: [{ name: 'Error', args: [], returns: [{ type: { kind: $.TypeKind.Basic, name: 'string' } }] }] } }] }, { name: "WriteByte", args: [{ name: "c", type: { kind: $.TypeKind.Basic, name: "number" } }], returns: [{ type: { kind: $.TypeKind.Interface, name: 'GoError', methods: [{ name: 'Error', args: [], returns: [{ type: { kind: $.TypeKind.Basic, name: 'string' } }] }] } }] }, { name: "WriteRune", args: [{ name: "r", type: { kind: $.TypeKind.Basic, name: "number" } }], returns: [{ type: { kind: $.TypeKind.Basic, name: "number" } }, { type: { kind: $.TypeKind.Interface, name: 'GoError', methods: [{ name: 'Error', args: [], returns: [{ type: { kind: $.TypeKind.Basic, name: 'string' } }] }] } }] }, { name: "Read", args: [{ name: "p", type: { kind: $.TypeKind.Slice, elemType: { kind: $.TypeKind.Basic, name: "number" } } }], returns: [{ type: { kind: $.TypeKind.Basic, name: "number" } }, { type: { kind: $.TypeKind.Interface, name: 'GoError', methods: [{ name: 'Error', args: [], returns: [{ type: { kind: $.TypeKind.Basic, name: 'string' } }] }] } }] }, { name: "Next", args: [{ name: "n", type: { kind: $.TypeKind.Basic, name: "number" } }], returns: [{ type: { kind: $.TypeKind.Slice, elemType: { kind: $.TypeKind.Basic, name: "number" } } }] }, { name: "ReadByte", args: [], returns: [{ type: { kind: $.TypeKind.Basic, name: "number" } }, { type: { kind: $.TypeKind.Interface, name: 'GoError', methods: [{ name: 'Error', args: [], returns: [{ type: { kind: $.TypeKind.Basic, name: 'string' } }] }] } }] }, { name: "ReadRune", args: [], returns: [{ type: { kind: $.TypeKind.Basic, name: "number" } }, { type: { kind: $.TypeKind.Basic, name: "number" } }, { type: { kind: $.TypeKind.Interface, name: 'GoError', methods: [{ name: 'Error', args: [], returns: [{ type: { kind: $.TypeKind.Basic, name: 'string' } }] }] } }] }, { name: "UnreadRune", args: [], returns: [{ type: { kind: $.TypeKind.Interface, name: 'GoError', methods: [{ name: 'Error', args: [], returns: [{ type: { kind: $.TypeKind.Basic, name: 'string' } }] }] } }] }, { name: "UnreadByte", args: [], returns: [{ type: { kind: $.TypeKind.Interface, name: 'GoError', methods: [{ name: 'Error', args: [], returns: [{ type: { kind: $.TypeKind.Basic, name: 'string' } }] }] } }] }, { name: "ReadBytes", args: [{ name: "delim", type: { kind: $.TypeKind.Basic, name: "number" } }], returns: [{ type: { kind: $.TypeKind.Slice, elemType: { kind: $.TypeKind.Basic, name: "number" } } }, { type: { kind: $.TypeKind.Interface, name: 'GoError', methods: [{ name: 'Error', args: [], returns: [{ type: { kind: $.TypeKind.Basic, name: 'string' } }] }] } }] }, { name: "readSlice", args: [{ name: "delim", type: { kind: $.TypeKind.Basic, name: "number" } }], returns: [{ type: { kind: $.TypeKind.Slice, elemType: { kind: $.TypeKind.Basic, name: "number" } } }, { type: { kind: $.TypeKind.Interface, name: 'GoError', methods: [{ name: 'Error', args: [], returns: [{ type: { kind: $.TypeKind.Basic, name: 'string' } }] }] } }] }, { name: "ReadString", args: [{ name: "delim", type: { kind: $.TypeKind.Basic, name: "number" } }], returns: [{ type: { kind: $.TypeKind.Basic, name: "string" } }, { type: { kind: $.TypeKind.Interface, name: 'GoError', methods: [{ name: 'Error', args: [], returns: [{ type: { kind: $.TypeKind.Basic, name: 'string' } }] }] } }] }],
551
551
  Buffer,
552
- {"buf": { kind: $.TypeKind.Slice, elemType: { kind: $.TypeKind.Basic, name: "number" } }, "off": { kind: $.TypeKind.Basic, name: "number" }, "lastRead": "readOp"}
552
+ [{ name: "buf", key: "buf", type: { kind: $.TypeKind.Slice, elemType: { kind: $.TypeKind.Basic, name: "number" } } }, { name: "off", key: "off", type: { kind: $.TypeKind.Basic, name: "number" } }, { name: "lastRead", key: "lastRead", type: "readOp" }]
553
553
  );
554
554
  }
555
555
 
@@ -221,7 +221,7 @@ export class Reader {
221
221
  new Reader(),
222
222
  [{ name: "Len", args: [], returns: [{ type: { kind: $.TypeKind.Basic, name: "number" } }] }, { name: "Size", args: [], returns: [{ type: { kind: $.TypeKind.Basic, name: "number" } }] }, { name: "Read", args: [{ name: "b", type: { kind: $.TypeKind.Slice, elemType: { kind: $.TypeKind.Basic, name: "number" } } }], returns: [{ type: { kind: $.TypeKind.Basic, name: "number" } }, { type: { kind: $.TypeKind.Interface, name: 'GoError', methods: [{ name: 'Error', args: [], returns: [{ type: { kind: $.TypeKind.Basic, name: 'string' } }] }] } }] }, { name: "ReadAt", args: [{ name: "b", type: { kind: $.TypeKind.Slice, elemType: { kind: $.TypeKind.Basic, name: "number" } } }, { name: "off", type: { kind: $.TypeKind.Basic, name: "number" } }], returns: [{ type: { kind: $.TypeKind.Basic, name: "number" } }, { type: { kind: $.TypeKind.Interface, name: 'GoError', methods: [{ name: 'Error', args: [], returns: [{ type: { kind: $.TypeKind.Basic, name: 'string' } }] }] } }] }, { name: "ReadByte", args: [], returns: [{ type: { kind: $.TypeKind.Basic, name: "number" } }, { type: { kind: $.TypeKind.Interface, name: 'GoError', methods: [{ name: 'Error', args: [], returns: [{ type: { kind: $.TypeKind.Basic, name: 'string' } }] }] } }] }, { name: "UnreadByte", args: [], returns: [{ type: { kind: $.TypeKind.Interface, name: 'GoError', methods: [{ name: 'Error', args: [], returns: [{ type: { kind: $.TypeKind.Basic, name: 'string' } }] }] } }] }, { name: "ReadRune", args: [], returns: [{ type: { kind: $.TypeKind.Basic, name: "number" } }, { type: { kind: $.TypeKind.Basic, name: "number" } }, { type: { kind: $.TypeKind.Interface, name: 'GoError', methods: [{ name: 'Error', args: [], returns: [{ type: { kind: $.TypeKind.Basic, name: 'string' } }] }] } }] }, { name: "UnreadRune", args: [], returns: [{ type: { kind: $.TypeKind.Interface, name: 'GoError', methods: [{ name: 'Error', args: [], returns: [{ type: { kind: $.TypeKind.Basic, name: 'string' } }] }] } }] }, { name: "Seek", args: [{ name: "offset", type: { kind: $.TypeKind.Basic, name: "number" } }, { name: "whence", type: { kind: $.TypeKind.Basic, name: "number" } }], returns: [{ type: { kind: $.TypeKind.Basic, name: "number" } }, { type: { kind: $.TypeKind.Interface, name: 'GoError', methods: [{ name: 'Error', args: [], returns: [{ type: { kind: $.TypeKind.Basic, name: 'string' } }] }] } }] }, { name: "WriteTo", args: [{ name: "w", type: "Writer" }], returns: [{ type: { kind: $.TypeKind.Basic, name: "number" } }, { type: { kind: $.TypeKind.Interface, name: 'GoError', methods: [{ name: 'Error', args: [], returns: [{ type: { kind: $.TypeKind.Basic, name: 'string' } }] }] } }] }, { name: "Reset", args: [{ name: "b", type: { kind: $.TypeKind.Slice, elemType: { kind: $.TypeKind.Basic, name: "number" } } }], returns: [] }],
223
223
  Reader,
224
- {"s": { kind: $.TypeKind.Slice, elemType: { kind: $.TypeKind.Basic, name: "number" } }, "i": { kind: $.TypeKind.Basic, name: "number" }, "prevRune": { kind: $.TypeKind.Basic, name: "number" }}
224
+ [{ name: "s", key: "s", type: { kind: $.TypeKind.Slice, elemType: { kind: $.TypeKind.Basic, name: "number" } } }, { name: "i", key: "i", type: { kind: $.TypeKind.Basic, name: "number" } }, { name: "prevRune", key: "prevRune", type: { kind: $.TypeKind.Basic, name: "number" } }]
225
225
  );
226
226
  }
227
227
 
@@ -4,9 +4,43 @@ import * as $ from '@goscript/builtin/index.js'
4
4
  import * as bytes from '@goscript/bytes/index.js'
5
5
  import * as io from '@goscript/io/index.js'
6
6
 
7
- import { NewReader, NewWriter } from './index.js'
7
+ import {
8
+ BestCompression,
9
+ BestSpeed,
10
+ DefaultCompression,
11
+ ErrChecksum,
12
+ ErrDictionary,
13
+ HuffmanOnly,
14
+ NewReader,
15
+ NewReaderDict,
16
+ NewWriter,
17
+ NewWriterLevel,
18
+ NewWriterLevelDict,
19
+ NoCompression,
20
+ } from './index.js'
8
21
 
9
22
  describe('compress/zlib override', () => {
23
+ test('exports flate compression level constants', () => {
24
+ expect(NoCompression).toBe(0)
25
+ expect(BestSpeed).toBe(1)
26
+ expect(BestCompression).toBe(9)
27
+ expect(DefaultCompression).toBe(-1)
28
+ expect(HuffmanOnly).toBe(-2)
29
+ })
30
+
31
+ test('rejects invalid compression levels', () => {
32
+ const buf = $.markAsStructValue(new bytes.Buffer())
33
+
34
+ expect(NewWriterLevel(buf, HuffmanOnly)[1]).toBeNull()
35
+ expect(NewWriterLevel(buf, BestCompression)[1]).toBeNull()
36
+ expect(NewWriterLevel(buf, HuffmanOnly - 1)[1]?.Error()).toBe(
37
+ 'zlib: invalid compression level: -3',
38
+ )
39
+ expect(NewWriterLevelDict(buf, BestCompression + 1, null)[1]?.Error()).toBe(
40
+ 'zlib: invalid compression level: 10',
41
+ )
42
+ })
43
+
10
44
  test('round trips bytes through writer and reader', async () => {
11
45
  const input = $.stringToBytes('hello compressed world')
12
46
  const buf = $.markAsStructValue(new bytes.Buffer())
@@ -25,4 +59,128 @@ describe('compress/zlib override', () => {
25
59
  expect(readErr).toBeNull()
26
60
  expect($.bytesToString(out)).toBe('hello compressed world')
27
61
  })
62
+
63
+ test('reader implements resettable zlib reader contract', async () => {
64
+ const first = $.markAsStructValue(new bytes.Buffer())
65
+ const firstWriter = NewWriter(first)
66
+ expect(firstWriter.Write($.stringToBytes('first stream'))[1]).toBeNull()
67
+ expect(await firstWriter.Close()).toBeNull()
68
+
69
+ const second = $.markAsStructValue(new bytes.Buffer())
70
+ const secondWriter = NewWriter(second)
71
+ expect(secondWriter.Write($.stringToBytes('second stream'))[1]).toBeNull()
72
+ expect(await secondWriter.Close()).toBeNull()
73
+
74
+ const readerInterface = $.registerInterfaceType(
75
+ 'compress/zlib.testReader',
76
+ null,
77
+ [
78
+ { name: 'Close', args: [], returns: [{ type: 'error' }] },
79
+ {
80
+ name: 'Read',
81
+ args: [
82
+ {
83
+ name: 'p',
84
+ type: {
85
+ kind: $.TypeKind.Slice,
86
+ elemType: { kind: $.TypeKind.Basic, name: 'uint8' },
87
+ },
88
+ },
89
+ ],
90
+ returns: [{ type: 'int' }, { type: 'error' }],
91
+ },
92
+ {
93
+ name: 'Reset',
94
+ args: [{ type: 'io.Reader' }, { type: '[]byte' }],
95
+ returns: [{ type: 'error' }],
96
+ },
97
+ ],
98
+ )
99
+
100
+ const [reader, readerErr] = NewReader(bytes.NewReader(first.Bytes()))
101
+ expect(readerErr).toBeNull()
102
+ const [zlibReader, ok] = $.typeAssertTuple<
103
+ io.ReadCloser & {
104
+ Reset(r: io.Reader | null, dict: $.Bytes | null): $.GoError
105
+ }
106
+ >(reader, readerInterface)
107
+ expect(ok).toBe(true)
108
+
109
+ const [firstOut, firstReadErr] = await io.ReadAll(zlibReader)
110
+ expect(firstReadErr).toBeNull()
111
+ expect($.bytesToString(firstOut)).toBe('first stream')
112
+
113
+ expect(zlibReader.Reset(bytes.NewReader(second.Bytes()), null)).toBeNull()
114
+ const [secondOut, secondReadErr] = await io.ReadAll(zlibReader)
115
+ expect(secondReadErr).toBeNull()
116
+ expect($.bytesToString(secondOut)).toBe('second stream')
117
+ })
118
+
119
+ test('writer and reader honor preset dictionaries', async () => {
120
+ const dict = $.stringToBytes('hello dictionary')
121
+ const compressed = $.markAsStructValue(new bytes.Buffer())
122
+ const [writer, writerErr] = NewWriterLevelDict(compressed, DefaultCompression, dict)
123
+ expect(writerErr).toBeNull()
124
+ expect(writer!.Write($.stringToBytes('hello dictionary payload'))[1]).toBeNull()
125
+ expect(await writer!.Close()).toBeNull()
126
+
127
+ const [missingDictReader, missingDictErr] = NewReader(bytes.NewReader(compressed.Bytes()))
128
+ expect(missingDictReader).toBeNull()
129
+ expect(missingDictErr).toBe(ErrDictionary)
130
+
131
+ const [reader, readerErr] = NewReaderDict(bytes.NewReader(compressed.Bytes()), dict)
132
+ expect(readerErr).toBeNull()
133
+ const [out, readErr] = await io.ReadAll(reader!)
134
+ expect(readErr).toBeNull()
135
+ expect($.bytesToString(out)).toBe('hello dictionary payload')
136
+
137
+ const [, wrongDictErr] = NewReaderDict(bytes.NewReader(compressed.Bytes()), $.stringToBytes('wrong dictionary'))
138
+ expect(wrongDictErr).toBe(ErrDictionary)
139
+
140
+ const corrupt = Uint8Array.from(compressed.Bytes())
141
+ corrupt[corrupt.length - 1] ^= 0xff
142
+ const [, corruptErr] = NewReaderDict(bytes.NewReader(corrupt), dict)
143
+ expect(corruptErr).toBe(ErrChecksum)
144
+ })
145
+
146
+ test('reader reset accepts async generated readers', async () => {
147
+ const compressed = $.markAsStructValue(new bytes.Buffer())
148
+ const writer = NewWriter(compressed)
149
+ expect(writer.Write($.stringToBytes('async source stream'))[1]).toBeNull()
150
+ expect(await writer.Close()).toBeNull()
151
+
152
+ const source = bytes.NewReader(compressed.Bytes())
153
+ const asyncReader = {
154
+ async Read(p: $.Bytes): Promise<[number, $.GoError]> {
155
+ await Promise.resolve()
156
+ return source.Read(p)
157
+ },
158
+ }
159
+
160
+ const [reader, readerErr] = NewReader(asyncReader as io.Reader)
161
+ expect(readerErr).toBeNull()
162
+ const [out, readErr] = await io.ReadAll(reader!)
163
+ expect(readErr).toBeNull()
164
+ expect($.bytesToString(out)).toBe('async source stream')
165
+ })
166
+
167
+ test('Close awaits pointer-wrapped generated writers', async () => {
168
+ const chunks: number[] = []
169
+ const sink = {
170
+ async Write(p: $.Bytes): Promise<[number, $.GoError]> {
171
+ await Promise.resolve()
172
+ chunks.push(...Array.from(p ?? []))
173
+ return [$.len(p), null]
174
+ },
175
+ }
176
+ const writer = NewWriter(
177
+ $.interfaceValue($.varRef(sink), '*zlib.asyncWriter'),
178
+ )
179
+
180
+ const [written, writeErr] = writer.Write($.stringToBytes('async zlib sink'))
181
+ expect(writeErr).toBeNull()
182
+ expect(written).toBe('async zlib sink'.length)
183
+ expect(await writer.Close()).toBeNull()
184
+ expect(chunks.length).toBeGreaterThan(0)
185
+ })
28
186
  })
@@ -3,13 +3,25 @@ import * as errors from '@goscript/errors/index.js'
3
3
  import * as io from '@goscript/io/index.js'
4
4
 
5
5
  export type Resetter = {
6
- Reset(r: io.Reader | null, dict: $.Bytes | null): Promise<$.GoError>
6
+ Reset(r: io.Reader | null, dict: $.Bytes | null): $.GoError
7
7
  }
8
8
 
9
+ type maybeAsyncWriter = {
10
+ Write(p: $.Bytes): [number, $.GoError] | Promise<[number, $.GoError]>
11
+ }
12
+
13
+ export const NoCompression = 0
14
+ export const BestSpeed = 1
15
+ export const BestCompression = 9
16
+ export const DefaultCompression = -1
17
+ export const HuffmanOnly = -2
18
+
9
19
  export let ErrChecksum = errors.New('zlib: invalid checksum')
10
20
  export let ErrDictionary = errors.New('zlib: invalid dictionary')
11
21
  export let ErrHeader = errors.New('zlib: invalid header')
12
22
 
23
+ type nodeZlibError = Error & { code?: unknown }
24
+
13
25
  export function __goscript_set_ErrChecksum(value: $.GoError): void {
14
26
  ErrChecksum = value
15
27
  }
@@ -22,12 +34,30 @@ export function __goscript_set_ErrHeader(value: $.GoError): void {
22
34
  ErrHeader = value
23
35
  }
24
36
 
25
- class zlibReader implements io.ReadCloser {
37
+ class zlibReader implements Resetter {
38
+ private data: Uint8Array = new Uint8Array(0)
26
39
  private offset = 0
40
+ private pending:
41
+ | Promise<{ data: Uint8Array | null; err: $.GoError }>
42
+ | null = null
27
43
 
28
- constructor(private data: Uint8Array) {}
44
+ constructor(data?: Uint8Array) {
45
+ if (data != null) {
46
+ this.data = data
47
+ }
48
+ }
29
49
 
30
- Read(p: $.Bytes): [number, $.GoError] {
50
+ async Read(p: $.Bytes): Promise<[number, $.GoError]> {
51
+ const pending = this.pending
52
+ if (pending != null) {
53
+ this.pending = null
54
+ const result = await pending
55
+ if (result.err != null) {
56
+ return [0, result.err]
57
+ }
58
+ this.data = result.data ?? new Uint8Array(0)
59
+ this.offset = 0
60
+ }
31
61
  if (this.offset >= this.data.length) {
32
62
  return [0, io.EOF]
33
63
  }
@@ -41,13 +71,37 @@ class zlibReader implements io.ReadCloser {
41
71
  Close(): $.GoError {
42
72
  return null
43
73
  }
74
+
75
+ Reset(r: io.Reader | null, dict: $.Bytes | null): $.GoError {
76
+ if (r == null) {
77
+ return errors.New('zlib: nil reader')
78
+ }
79
+ const result = readInflated(r, dict)
80
+ if (result instanceof Promise) {
81
+ this.data = new Uint8Array(0)
82
+ this.offset = 0
83
+ this.pending = result
84
+ return null
85
+ }
86
+ if (result.err != null) {
87
+ return result.err
88
+ }
89
+ this.data = result.data ?? new Uint8Array(0)
90
+ this.offset = 0
91
+ this.pending = null
92
+ return null
93
+ }
44
94
  }
45
95
 
46
96
  export class Writer {
47
97
  private chunks: Uint8Array[] = []
48
98
  private closed = false
49
99
 
50
- constructor(private w: io.Writer | null) {}
100
+ constructor(
101
+ private w: io.Writer | null,
102
+ private dict: $.Bytes | null = null,
103
+ private level = DefaultCompression,
104
+ ) {}
51
105
 
52
106
  Write(p: $.Bytes): [number, $.GoError] {
53
107
  if (this.closed) {
@@ -58,7 +112,7 @@ export class Writer {
58
112
  return [data.length, null]
59
113
  }
60
114
 
61
- Close(): $.GoError {
115
+ async Close(): Promise<$.GoError> {
62
116
  if (this.closed) {
63
117
  return null
64
118
  }
@@ -66,8 +120,9 @@ export class Writer {
66
120
  if (this.w == null) {
67
121
  return errors.New('zlib: nil writer')
68
122
  }
69
- const compressed = deflate(concat(this.chunks))
70
- const [, err] = this.w.Write(compressed)
123
+ const compressed = deflate(concat(this.chunks), this.dict, this.level)
124
+ const writer = $.pointerValue<maybeAsyncWriter>(this.w)
125
+ const [, err] = await writer.Write(compressed)
71
126
  return err
72
127
  }
73
128
 
@@ -88,17 +143,23 @@ export function NewWriter(w: io.Writer | null): Writer {
88
143
 
89
144
  export function NewWriterLevel(
90
145
  w: io.Writer | null,
91
- _level: number,
146
+ level: number,
92
147
  ): [Writer | null, $.GoError] {
93
- return [new Writer(w), null]
148
+ if (level < HuffmanOnly || level > BestCompression) {
149
+ return [null, errors.New(`zlib: invalid compression level: ${level}`)]
150
+ }
151
+ return [new Writer(w, null, level), null]
94
152
  }
95
153
 
96
154
  export function NewWriterLevelDict(
97
155
  w: io.Writer | null,
98
- _level: number,
156
+ level: number,
99
157
  _dict: $.Bytes | null,
100
158
  ): [Writer | null, $.GoError] {
101
- return [new Writer(w), null]
159
+ if (level < HuffmanOnly || level > BestCompression) {
160
+ return [null, errors.New(`zlib: invalid compression level: ${level}`)]
161
+ }
162
+ return [new Writer(w, _dict, level), null]
102
163
  }
103
164
 
104
165
  export function NewReader(
@@ -109,31 +170,35 @@ export function NewReader(
109
170
 
110
171
  export function NewReaderDict(
111
172
  r: io.Reader | null,
112
- _dict: $.Bytes | null,
173
+ dict: $.Bytes | null,
113
174
  ): [io.ReadCloser | null, $.GoError] {
114
- if (r == null) {
115
- return [null, errors.New('zlib: nil reader')]
116
- }
117
- const [data, readErr] = readAll(r)
118
- if (readErr != null) {
119
- return [null, readErr]
120
- }
121
- try {
122
- const out = inflate($.bytesToUint8Array(data))
123
- return [new zlibReader(out), null]
124
- } catch {
125
- return [null, ErrHeader]
175
+ const reader = new zlibReader()
176
+ const err = reader.Reset(r, dict)
177
+ if (err != null) {
178
+ return [null, err]
126
179
  }
180
+ return [reader as any, null]
127
181
  }
128
182
 
129
- function deflate(data: Uint8Array): Uint8Array {
183
+ function deflate(data: Uint8Array, dict: $.Bytes | null, level: number): Uint8Array {
130
184
  const zlib = nodeZlib()
131
- return new Uint8Array(zlib.deflateSync(data))
185
+ const opts: Record<string, unknown> = {}
186
+ if (dict != null && $.len(dict) > 0) {
187
+ opts.dictionary = $.bytesToUint8Array(dict)
188
+ }
189
+ if (level === HuffmanOnly) {
190
+ opts.strategy = zlib.constants?.Z_HUFFMAN_ONLY
191
+ opts.level = DefaultCompression
192
+ } else {
193
+ opts.level = level
194
+ }
195
+ return new Uint8Array(zlib.deflateSync(data, opts))
132
196
  }
133
197
 
134
- function inflate(data: Uint8Array): Uint8Array {
198
+ function inflate(data: Uint8Array, dict: $.Bytes | null): Uint8Array {
135
199
  const zlib = nodeZlib()
136
- return new Uint8Array(zlib.inflateSync(data))
200
+ const opts = dict != null && $.len(dict) > 0 ? { dictionary: $.bytesToUint8Array(dict) } : undefined
201
+ return new Uint8Array(zlib.inflateSync(data, opts))
137
202
  }
138
203
 
139
204
  function nodeZlib(): any {
@@ -168,23 +233,85 @@ function nodeZlib(): any {
168
233
  throw new Error('compress/zlib: node zlib module unavailable')
169
234
  }
170
235
 
171
- function readAll(r: io.Reader): [Uint8Array, $.GoError] {
172
- const chunks: Uint8Array[] = []
173
- const buf = $.makeSlice<number>(32 * 1024, undefined, 'byte')
236
+ function readInflated(
237
+ r: io.Reader,
238
+ dict: $.Bytes | null,
239
+ ):
240
+ | { data: Uint8Array | null; err: $.GoError }
241
+ | Promise<{ data: Uint8Array | null; err: $.GoError }> {
242
+ const chunks: number[] = []
243
+ const buf = $.makeSlice<number>(1, undefined, 'byte')
174
244
  while (true) {
175
- const [n, err] = r.Read(buf)
176
- if (n > 0) {
177
- chunks.push($.bytesToUint8Array($.goSlice(buf, 0, n)).slice())
245
+ const read = r.Read(buf)
246
+ if (read instanceof Promise) {
247
+ return readInflatedAsync(read, r, buf, chunks, dict)
248
+ }
249
+ const [n, err] = read
250
+ const result = recordCompressedBytes(chunks, buf, n, dict)
251
+ if (result.err == null && result.data != null) {
252
+ return result
178
253
  }
179
254
  if (err != null) {
180
255
  if (err === io.EOF) {
181
- return [concat(chunks), null]
256
+ return result
182
257
  }
183
- return [new Uint8Array(0), err]
258
+ return { data: null, err }
184
259
  }
185
260
  }
186
261
  }
187
262
 
263
+ async function readInflatedAsync(
264
+ first: Promise<[number, $.GoError]>,
265
+ r: io.Reader,
266
+ buf: $.Bytes,
267
+ chunks: number[],
268
+ dict: $.Bytes | null,
269
+ ): Promise<{ data: Uint8Array | null; err: $.GoError }> {
270
+ let read = await first
271
+ while (true) {
272
+ const [n, err] = read
273
+ const result = recordCompressedBytes(chunks, buf, n, dict)
274
+ if (result.err == null && result.data != null) {
275
+ return result
276
+ }
277
+ if (err != null) {
278
+ if (err === io.EOF) {
279
+ return result
280
+ }
281
+ return { data: null, err }
282
+ }
283
+ read = await r.Read(buf)
284
+ }
285
+ }
286
+
287
+ function recordCompressedBytes(
288
+ chunks: number[],
289
+ buf: $.Bytes,
290
+ n: number,
291
+ dict: $.Bytes | null,
292
+ ): { data: Uint8Array | null; err: $.GoError } {
293
+ if (n > 0) {
294
+ chunks.push(...$.bytesToUint8Array($.goSlice(buf, 0, n)))
295
+ }
296
+ const compressed = new Uint8Array(chunks)
297
+ try {
298
+ return { data: inflate(compressed, dict), err: null }
299
+ } catch (err) {
300
+ return { data: null, err: classifyInflateError(err) }
301
+ }
302
+ }
303
+
304
+ function classifyInflateError(err: unknown): $.GoError {
305
+ const zerr = err instanceof Error ? err as nodeZlibError : null
306
+ if (zerr?.code === 'Z_NEED_DICT') {
307
+ return ErrDictionary
308
+ }
309
+ if (zerr?.code === 'Z_DATA_ERROR' && zerr.message.includes('incorrect data check')) {
310
+ return ErrChecksum
311
+ }
312
+ return ErrHeader
313
+ }
314
+
188
315
  function concat(chunks: Uint8Array[]): Uint8Array {
189
316
  let total = 0
190
317
  for (const chunk of chunks) {
@@ -1,3 +1,6 @@
1
1
  {
2
- "dependencies": []
2
+ "dependencies": [],
3
+ "asyncMethods": {
4
+ "Writer.Close": true
5
+ }
3
6
  }
@@ -0,0 +1,51 @@
1
+ {
2
+ "schemaVersion": 1,
3
+ "strict": true,
4
+ "symbols": {
5
+ "BestCompression": {
6
+ "status": "real"
7
+ },
8
+ "BestSpeed": {
9
+ "status": "real"
10
+ },
11
+ "DefaultCompression": {
12
+ "status": "real"
13
+ },
14
+ "ErrChecksum": {
15
+ "status": "real"
16
+ },
17
+ "ErrDictionary": {
18
+ "status": "real"
19
+ },
20
+ "ErrHeader": {
21
+ "status": "real"
22
+ },
23
+ "HuffmanOnly": {
24
+ "status": "real"
25
+ },
26
+ "NewReader": {
27
+ "status": "real"
28
+ },
29
+ "NewReaderDict": {
30
+ "status": "real"
31
+ },
32
+ "NewWriter": {
33
+ "status": "real"
34
+ },
35
+ "NewWriterLevel": {
36
+ "status": "real"
37
+ },
38
+ "NewWriterLevelDict": {
39
+ "status": "real"
40
+ },
41
+ "NoCompression": {
42
+ "status": "real"
43
+ },
44
+ "Resetter": {
45
+ "status": "real"
46
+ },
47
+ "Writer": {
48
+ "status": "real"
49
+ }
50
+ }
51
+ }