goscript 0.0.38 → 0.0.40

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 (180) hide show
  1. package/compiler/analysis.go +15 -6
  2. package/compiler/compiler.go +184 -34
  3. package/compiler/expr-call.go +19 -9
  4. package/compiler/field.go +17 -3
  5. package/compiler/gs_dependencies_test.go +80 -0
  6. package/compiler/lit.go +12 -6
  7. package/compiler/output.go +10 -4
  8. package/compiler/spec.go +15 -2
  9. package/compiler/type-assert.go +111 -21
  10. package/compiler/type.go +37 -8
  11. package/dist/gs/builtin/builtin.d.ts +55 -0
  12. package/dist/gs/builtin/builtin.js +213 -0
  13. package/dist/gs/builtin/builtin.js.map +1 -1
  14. package/dist/gs/builtin/slice.js +13 -0
  15. package/dist/gs/builtin/slice.js.map +1 -1
  16. package/dist/gs/bytes/buffer.gs.d.ts +56 -0
  17. package/dist/gs/bytes/buffer.gs.js +611 -0
  18. package/dist/gs/bytes/buffer.gs.js.map +1 -0
  19. package/dist/gs/bytes/bytes.gs.d.ts +78 -0
  20. package/dist/gs/bytes/bytes.gs.js +1107 -0
  21. package/dist/gs/bytes/bytes.gs.js.map +1 -0
  22. package/dist/gs/bytes/index.d.ts +4 -0
  23. package/dist/gs/bytes/index.js +5 -0
  24. package/dist/gs/bytes/index.js.map +1 -0
  25. package/dist/gs/bytes/iter.gs.d.ts +9 -0
  26. package/dist/gs/bytes/iter.gs.js +143 -0
  27. package/dist/gs/bytes/iter.gs.js.map +1 -0
  28. package/dist/gs/bytes/reader.gs.d.ts +34 -0
  29. package/dist/gs/bytes/reader.gs.js +198 -0
  30. package/dist/gs/bytes/reader.gs.js.map +1 -0
  31. package/dist/gs/fmt/fmt.d.ts +49 -0
  32. package/dist/gs/fmt/fmt.js +322 -0
  33. package/dist/gs/fmt/fmt.js.map +1 -0
  34. package/dist/gs/fmt/index.d.ts +1 -0
  35. package/dist/gs/fmt/index.js +2 -0
  36. package/dist/gs/fmt/index.js.map +1 -0
  37. package/dist/gs/internal/bytealg/index.d.ts +14 -2
  38. package/dist/gs/internal/bytealg/index.js +114 -8
  39. package/dist/gs/internal/bytealg/index.js.map +1 -1
  40. package/dist/gs/path/filepath/index.d.ts +3 -0
  41. package/dist/gs/path/filepath/index.js +3 -0
  42. package/dist/gs/path/filepath/index.js.map +1 -0
  43. package/dist/gs/path/filepath/match.d.ts +3 -0
  44. package/dist/gs/path/filepath/match.js +212 -0
  45. package/dist/gs/path/filepath/match.js.map +1 -0
  46. package/dist/gs/path/filepath/path.d.ts +25 -0
  47. package/dist/gs/path/filepath/path.js +265 -0
  48. package/dist/gs/path/filepath/path.js.map +1 -0
  49. package/dist/gs/reflect/deepequal.d.ts +2 -1
  50. package/dist/gs/reflect/deepequal.js +5 -53
  51. package/dist/gs/reflect/deepequal.js.map +1 -1
  52. package/dist/gs/reflect/map.d.ts +14 -8
  53. package/dist/gs/reflect/map.js +15 -11
  54. package/dist/gs/reflect/map.js.map +1 -1
  55. package/dist/gs/reflect/type.d.ts +17 -9
  56. package/dist/gs/reflect/type.js +1 -1
  57. package/dist/gs/reflect/type.js.map +1 -1
  58. package/dist/gs/reflect/value.js +15 -6
  59. package/dist/gs/reflect/value.js.map +1 -1
  60. package/dist/gs/reflect/visiblefields.js +18 -12
  61. package/dist/gs/reflect/visiblefields.js.map +1 -1
  62. package/dist/gs/sort/index.d.ts +4 -0
  63. package/dist/gs/sort/index.js +4 -0
  64. package/dist/gs/sort/index.js.map +1 -0
  65. package/dist/gs/sort/search.gs.d.ts +6 -0
  66. package/dist/gs/sort/search.gs.js +125 -0
  67. package/dist/gs/sort/search.gs.js.map +1 -0
  68. package/dist/gs/sort/slice.gs.d.ts +4 -0
  69. package/dist/gs/sort/slice.gs.js +49 -0
  70. package/dist/gs/sort/slice.gs.js.map +1 -0
  71. package/dist/gs/sort/sort.gs.d.ts +37 -0
  72. package/dist/gs/sort/sort.gs.js +203 -0
  73. package/dist/gs/sort/sort.gs.js.map +1 -0
  74. package/dist/gs/unicode/utf8/utf8.d.ts +1 -1
  75. package/dist/gs/unicode/utf8/utf8.js +4 -2
  76. package/dist/gs/unicode/utf8/utf8.js.map +1 -1
  77. package/gs/builtin/builtin.ts +236 -0
  78. package/gs/builtin/slice.ts +17 -1
  79. package/gs/bytes/buffer.gs.ts +614 -0
  80. package/gs/bytes/bytes.gs.ts +1288 -0
  81. package/gs/bytes/godoc.txt +69 -0
  82. package/gs/bytes/index.ts +69 -0
  83. package/gs/bytes/iter.gs.ts +149 -0
  84. package/gs/bytes/metadata.go +12 -0
  85. package/gs/bytes/reader.gs.ts +230 -0
  86. package/gs/fmt/fmt.ts +407 -0
  87. package/gs/fmt/godoc.txt +382 -0
  88. package/gs/fmt/index.ts +31 -0
  89. package/gs/fmt/metadata.go +7 -0
  90. package/gs/internal/bytealg/index.ts +125 -10
  91. package/gs/internal/metadata.go +7 -0
  92. package/gs/io/metadata.go +11 -0
  93. package/gs/maps/metadata.go +8 -0
  94. package/gs/math/metadata.go +7 -0
  95. package/gs/os/metadata.go +17 -0
  96. package/gs/path/filepath/godoc.txt +35 -0
  97. package/gs/path/filepath/index.ts +27 -0
  98. package/gs/path/filepath/match.test.ts +274 -0
  99. package/gs/path/filepath/match.ts +249 -0
  100. package/gs/path/filepath/path.test.ts +246 -0
  101. package/gs/path/filepath/path.ts +328 -0
  102. package/gs/path/metadata.go +8 -0
  103. package/gs/reflect/deepequal.test.ts +41 -0
  104. package/gs/reflect/deepequal.ts +19 -4
  105. package/gs/reflect/map.test.ts +30 -0
  106. package/gs/reflect/map.ts +22 -18
  107. package/gs/reflect/metadata.go +7 -0
  108. package/gs/reflect/type.ts +19 -15
  109. package/gs/reflect/value.ts +21 -7
  110. package/gs/reflect/visiblefields.ts +17 -13
  111. package/gs/sort/godoc.txt +27 -0
  112. package/gs/sort/index.ts +24 -0
  113. package/gs/sort/search.gs.ts +128 -0
  114. package/gs/sort/slice.gs.ts +59 -0
  115. package/gs/sort/sort.gs.ts +227 -0
  116. package/gs/strconv/metadata.go +7 -0
  117. package/gs/strings/metadata.go +11 -0
  118. package/gs/sync/metadata.go +7 -0
  119. package/gs/unicode/utf8/utf8.ts +8 -5
  120. package/package.json +1 -1
  121. package/dist/gs/internal/testlog/index.d.ts +0 -1
  122. package/dist/gs/internal/testlog/index.js +0 -5
  123. package/dist/gs/internal/testlog/index.js.map +0 -1
  124. package/dist/gs/maps/iter.gs.d.ts +0 -7
  125. package/dist/gs/maps/iter.gs.js +0 -65
  126. package/dist/gs/maps/iter.gs.js.map +0 -1
  127. package/dist/gs/maps/maps.gs.d.ts +0 -7
  128. package/dist/gs/maps/maps.gs.js +0 -79
  129. package/dist/gs/maps/maps.gs.js.map +0 -1
  130. package/dist/gs/reflect/abi.d.ts +0 -59
  131. package/dist/gs/reflect/abi.gs.d.ts +0 -59
  132. package/dist/gs/reflect/abi.gs.js +0 -79
  133. package/dist/gs/reflect/abi.gs.js.map +0 -1
  134. package/dist/gs/reflect/abi.js +0 -79
  135. package/dist/gs/reflect/abi.js.map +0 -1
  136. package/dist/gs/reflect/badlinkname.d.ts +0 -52
  137. package/dist/gs/reflect/badlinkname.gs.d.ts +0 -52
  138. package/dist/gs/reflect/badlinkname.gs.js +0 -72
  139. package/dist/gs/reflect/badlinkname.gs.js.map +0 -1
  140. package/dist/gs/reflect/badlinkname.js +0 -72
  141. package/dist/gs/reflect/badlinkname.js.map +0 -1
  142. package/dist/gs/reflect/deepequal.gs.d.ts +0 -25
  143. package/dist/gs/reflect/deepequal.gs.js +0 -308
  144. package/dist/gs/reflect/deepequal.gs.js.map +0 -1
  145. package/dist/gs/reflect/float32reg_generic.gs.d.ts +0 -2
  146. package/dist/gs/reflect/float32reg_generic.gs.js +0 -10
  147. package/dist/gs/reflect/float32reg_generic.gs.js.map +0 -1
  148. package/dist/gs/reflect/index.gs.d.ts +0 -1
  149. package/dist/gs/reflect/index.gs.js +0 -3
  150. package/dist/gs/reflect/index.gs.js.map +0 -1
  151. package/dist/gs/reflect/iter.gs.d.ts +0 -3
  152. package/dist/gs/reflect/iter.gs.js +0 -24
  153. package/dist/gs/reflect/iter.gs.js.map +0 -1
  154. package/dist/gs/reflect/makefunc.gs.d.ts +0 -34
  155. package/dist/gs/reflect/makefunc.gs.js +0 -288
  156. package/dist/gs/reflect/makefunc.gs.js.map +0 -1
  157. package/dist/gs/reflect/map_swiss.gs.d.ts +0 -14
  158. package/dist/gs/reflect/map_swiss.gs.js +0 -70
  159. package/dist/gs/reflect/map_swiss.gs.js.map +0 -1
  160. package/dist/gs/reflect/reflect.gs.d.ts +0 -132
  161. package/dist/gs/reflect/reflect.gs.js +0 -437
  162. package/dist/gs/reflect/reflect.gs.js.map +0 -1
  163. package/dist/gs/reflect/swapper.gs.d.ts +0 -1
  164. package/dist/gs/reflect/swapper.gs.js +0 -32
  165. package/dist/gs/reflect/swapper.gs.js.map +0 -1
  166. package/dist/gs/reflect/type.gs.d.ts +0 -4
  167. package/dist/gs/reflect/type.gs.js +0 -21
  168. package/dist/gs/reflect/type.gs.js.map +0 -1
  169. package/dist/gs/reflect/value.gs.d.ts +0 -4
  170. package/dist/gs/reflect/value.gs.js +0 -12
  171. package/dist/gs/reflect/value.gs.js.map +0 -1
  172. package/dist/gs/reflect/visiblefields.gs.d.ts +0 -3
  173. package/dist/gs/reflect/visiblefields.gs.js +0 -123
  174. package/dist/gs/reflect/visiblefields.gs.js.map +0 -1
  175. package/dist/gs/stringslite/index.d.ts +0 -1
  176. package/dist/gs/stringslite/index.js +0 -2
  177. package/dist/gs/stringslite/index.js.map +0 -1
  178. package/dist/gs/stringslite/strings.d.ts +0 -11
  179. package/dist/gs/stringslite/strings.js +0 -67
  180. package/dist/gs/stringslite/strings.js.map +0 -1
@@ -0,0 +1,1288 @@
1
+ import * as $ from "@goscript/builtin/builtin.js";
2
+
3
+
4
+ import * as unicode from "@goscript/unicode/index.js"
5
+
6
+ import * as utf8 from "@goscript/unicode/utf8/index.js"
7
+
8
+ // for linkname
9
+ import * as _ from "@goscript/unsafe/index.js"
10
+
11
+ // Equal reports whether a and b
12
+ // are the same length and contain the same bytes.
13
+ // A nil argument is equivalent to an empty slice.
14
+ export function Equal(a: $.Bytes, b: $.Bytes): boolean {
15
+ return $.bytesEqual(a, b)
16
+ }
17
+
18
+ // Compare returns an integer comparing two byte slices lexicographically.
19
+ // The result will be 0 if a == b, -1 if a < b, and +1 if a > b.
20
+ // A nil argument is equivalent to an empty slice.
21
+ export function Compare(a: $.Bytes, b: $.Bytes): number {
22
+ return $.bytesCompare(a, b)
23
+ }
24
+
25
+ // explode splits s into a slice of UTF-8 sequences, one per Unicode code point (still slices of bytes),
26
+ // up to a maximum of n byte slices. Invalid UTF-8 sequences are chopped into individual bytes.
27
+ export function explode(s: $.Bytes, n: number): $.Slice<$.Bytes> {
28
+ if (n === 0) {
29
+ return null
30
+ }
31
+
32
+ if (s === null || $.len(s) === 0) {
33
+ return null
34
+ }
35
+
36
+ const result: $.Bytes[] = []
37
+ let i = 0
38
+
39
+ while (i < $.len(s) && (n < 0 || result.length < n)) {
40
+ const [, size] = utf8.DecodeRune($.goSlice(s, i, undefined))
41
+ if (size <= 0) {
42
+ // Invalid UTF-8, take single byte
43
+ result.push($.goSlice(s, i, i + 1))
44
+ i++
45
+ } else {
46
+ result.push($.goSlice(s, i, i + size))
47
+ i += size
48
+ }
49
+ }
50
+
51
+ // If we have remaining bytes and haven't reached n limit, add the rest
52
+ if (i < $.len(s) && (n < 0 || result.length < n)) {
53
+ result.push($.goSlice(s, i, undefined))
54
+ }
55
+
56
+ return $.arrayToSlice(result)
57
+ }
58
+
59
+ // Count counts the number of non-overlapping instances of sep in s.
60
+ // If sep is an empty slice, Count returns 1 + the number of UTF-8-encoded code points in s.
61
+ export function Count(s: $.Bytes, sep: $.Bytes): number {
62
+ // Special case for empty separator
63
+ if (sep === null || $.len(sep) === 0) {
64
+ if (s === null) return 1
65
+ // For now, use simple byte count + 1 (TODO: proper UTF-8 rune counting)
66
+ return $.len(s) + 1
67
+ }
68
+
69
+ // Single byte separator - optimized path
70
+ if ($.len(sep) === 1) {
71
+ return $.bytesCount(s, sep)
72
+ }
73
+
74
+ return $.bytesCount(s, sep)
75
+ }
76
+
77
+ // Contains reports whether subslice is within b.
78
+ export function Contains(b: $.Bytes, subslice: $.Bytes): boolean {
79
+ return Index(b, subslice) !== -1
80
+ }
81
+
82
+ // ContainsAny reports whether any of the UTF-8-encoded code points in chars are within b.
83
+ export function ContainsAny(b: $.Bytes, chars: string): boolean {
84
+ return IndexAny(b, chars) >= 0
85
+ }
86
+
87
+ // ContainsRune reports whether the rune is contained in the UTF-8-encoded byte slice b.
88
+ export function ContainsRune(b: $.Bytes, r: number): boolean {
89
+ return IndexRune(b, r) >= 0
90
+ }
91
+
92
+ // ContainsFunc reports whether any of the UTF-8-encoded code points r within b satisfy f(r).
93
+ export function ContainsFunc(b: $.Bytes, f: ((p0: number) => boolean) | null): boolean {
94
+ return IndexFunc(b, f) >= 0
95
+ }
96
+
97
+ // IndexByte returns the index of the first instance of c in b, or -1 if c is not present in b.
98
+ export function IndexByte(b: $.Bytes, c: number): number {
99
+ return $.bytesIndexByte(b, c)
100
+ }
101
+
102
+ export function indexBytePortable(s: $.Bytes, c: number): number {
103
+ if (s === null) return -1
104
+ const arr = $.bytesToArray(s)
105
+ return arr.indexOf(c)
106
+ }
107
+
108
+ // LastIndex returns the index of the last instance of sep in s, or -1 if sep is not present in s.
109
+ export function LastIndex(s: $.Bytes, sep: $.Bytes): number {
110
+ if (sep === null || $.len(sep) === 0) {
111
+ return s === null ? 0 : $.len(s)
112
+ }
113
+
114
+ if ($.len(sep) === 1) {
115
+ return $.bytesLastIndexByte(s, sep![0])
116
+ }
117
+
118
+ return $.bytesLastIndexOf(s, sep)
119
+ }
120
+
121
+ // LastIndexByte returns the index of the last instance of c in s, or -1 if c is not present in s.
122
+ export function LastIndexByte(s: $.Bytes, c: number): number {
123
+ return $.bytesLastIndexByte(s, c)
124
+ }
125
+
126
+ // IndexRune interprets s as a sequence of UTF-8-encoded code points.
127
+ // It returns the byte index of the first occurrence in s of the given rune.
128
+ // It returns -1 if rune is not present in s.
129
+ // If r is [utf8.RuneError], it returns the first instance of any
130
+ // invalid UTF-8 byte sequence.
131
+ export function IndexRune(s: $.Bytes, r: number): number {
132
+ if (s === null) {
133
+ return -1
134
+ }
135
+
136
+ if (r < utf8.RuneSelf) {
137
+ // ASCII case - use IndexByte for efficiency
138
+ return IndexByte(s, r)
139
+ }
140
+
141
+ if (r === utf8.RuneError) {
142
+ // Look for invalid UTF-8 sequences
143
+ for (let i = 0; i < $.len(s); ) {
144
+ const [r1, size] = utf8.DecodeRune($.goSlice(s, i, undefined))
145
+ if (r1 === utf8.RuneError && size === 1) {
146
+ return i
147
+ }
148
+ if (size <= 0) {
149
+ return i
150
+ }
151
+ i += size
152
+ }
153
+ return -1
154
+ }
155
+
156
+ // Encode the rune to bytes and search for it
157
+ const runeBytes = new Uint8Array(4)
158
+ const n = utf8.EncodeRune(runeBytes as $.Bytes, r)
159
+ const needle = $.goSlice(runeBytes as $.Bytes, 0, n)
160
+
161
+ return Index(s, needle)
162
+ }
163
+
164
+ // IndexAny interprets s as a sequence of UTF-8-encoded Unicode code points.
165
+ // It returns the byte index of the first occurrence in s of any of the Unicode
166
+ // code points in chars. It returns -1 if chars is empty or if there is no code
167
+ // point in common.
168
+ export function IndexAny(s: $.Bytes, chars: string): number {
169
+ if (s === null || chars.length === 0) {
170
+ return -1
171
+ }
172
+
173
+ // Check if all chars are ASCII for optimization
174
+ let allASCII = true
175
+ for (let i = 0; i < chars.length; i++) {
176
+ if (chars.charCodeAt(i) >= utf8.RuneSelf) {
177
+ allASCII = false
178
+ break
179
+ }
180
+ }
181
+
182
+ if (allASCII) {
183
+ // ASCII optimization
184
+ for (let i = 0; i < $.len(s); i++) {
185
+ const b = s![i]
186
+ if (b < utf8.RuneSelf && chars.indexOf(String.fromCharCode(b)) >= 0) {
187
+ return i
188
+ }
189
+ }
190
+ return -1
191
+ }
192
+
193
+ // Full UTF-8 handling
194
+ for (let i = 0; i < $.len(s); ) {
195
+ const [r, size] = utf8.DecodeRune($.goSlice(s, i, undefined))
196
+ if (size <= 0) {
197
+ i++
198
+ continue
199
+ }
200
+
201
+ // Check if this rune is in chars
202
+ if (containsRune(chars, r)) {
203
+ return i
204
+ }
205
+
206
+ i += size
207
+ }
208
+
209
+ return -1
210
+ }
211
+
212
+ // LastIndexAny interprets s as a sequence of UTF-8-encoded Unicode code
213
+ // points. It returns the byte index of the last occurrence in s of any of
214
+ // the Unicode code points in chars. It returns -1 if chars is empty or if
215
+ // there is no code point in common.
216
+ export function LastIndexAny(s: $.Bytes, chars: string): number {
217
+ if (s === null || chars.length === 0) {
218
+ return -1
219
+ }
220
+
221
+ // Check if all chars are ASCII for optimization
222
+ let allASCII = true
223
+ for (let i = 0; i < chars.length; i++) {
224
+ if (chars.charCodeAt(i) >= utf8.RuneSelf) {
225
+ allASCII = false
226
+ break
227
+ }
228
+ }
229
+
230
+ if (allASCII) {
231
+ // ASCII optimization - search backwards
232
+ for (let i = $.len(s) - 1; i >= 0; i--) {
233
+ const b = s![i]
234
+ if (b < utf8.RuneSelf && chars.indexOf(String.fromCharCode(b)) >= 0) {
235
+ return i
236
+ }
237
+ }
238
+ return -1
239
+ }
240
+
241
+ // Full UTF-8 handling - need to scan forward to find rune boundaries
242
+ let lastIndex = -1
243
+ for (let i = 0; i < $.len(s); ) {
244
+ const [r, size] = utf8.DecodeRune($.goSlice(s, i, undefined))
245
+ if (size <= 0) {
246
+ i++
247
+ continue
248
+ }
249
+
250
+ // Check if this rune is in chars
251
+ if (containsRune(chars, r)) {
252
+ lastIndex = i
253
+ }
254
+
255
+ i += size
256
+ }
257
+
258
+ return lastIndex
259
+ }
260
+
261
+ // Generic split: splits after each instance of sep,
262
+ // including sepSave bytes of sep in the subslices.
263
+ export function genSplit(s: $.Bytes, sep: $.Bytes, sepSave: number, n: number): $.Slice<$.Bytes> {
264
+ if (n === 0) {
265
+ return null
266
+ }
267
+
268
+ if (sep === null || $.len(sep) === 0) {
269
+ return explode(s, n)
270
+ }
271
+
272
+ if (n < 0) {
273
+ n = Count(s, sep) + 1
274
+ }
275
+
276
+ if (n > Count(s, sep) + 1) {
277
+ n = Count(s, sep) + 1
278
+ }
279
+
280
+ const result: $.Bytes[] = []
281
+ let start = 0
282
+
283
+ for (let i = 0; i < n - 1; i++) {
284
+ const m = Index($.goSlice(s, start, undefined), sep)
285
+ if (m < 0) {
286
+ break
287
+ }
288
+ const end = start + m + sepSave
289
+ result.push($.goSlice(s, start, end))
290
+ start += m + $.len(sep)
291
+ }
292
+
293
+ // Add the remaining part
294
+ result.push($.goSlice(s, start, undefined))
295
+
296
+ return $.arrayToSlice(result)
297
+ }
298
+
299
+ // SplitN slices s into subslices separated by sep and returns a slice of
300
+ // the subslices between those separators.
301
+ // If sep is empty, SplitN splits after each UTF-8 sequence.
302
+ // The count determines the number of subslices to return:
303
+ // - n > 0: at most n subslices; the last subslice will be the unsplit remainder;
304
+ // - n == 0: the result is nil (zero subslices);
305
+ // - n < 0: all subslices.
306
+ //
307
+ // To split around the first instance of a separator, see [Cut].
308
+ export function SplitN(s: $.Bytes, sep: $.Bytes, n: number): $.Slice<$.Bytes> {
309
+ return genSplit(s, sep, 0, n)
310
+ }
311
+
312
+ // SplitAfterN slices s into subslices after each instance of sep and
313
+ // returns a slice of those subslices.
314
+ // If sep is empty, SplitAfterN splits after each UTF-8 sequence.
315
+ // The count determines the number of subslices to return:
316
+ // - n > 0: at most n subslices; the last subslice will be the unsplit remainder;
317
+ // - n == 0: the result is nil (zero subslices);
318
+ // - n < 0: all subslices.
319
+ export function SplitAfterN(s: $.Bytes, sep: $.Bytes, n: number): $.Slice<$.Bytes> {
320
+ return genSplit(s, sep, $.len(sep), n)
321
+ }
322
+
323
+ // Split slices s into all subslices separated by sep and returns a slice of
324
+ // the subslices between those separators.
325
+ // If sep is empty, Split splits after each UTF-8 sequence.
326
+ // It is equivalent to SplitN with a count of -1.
327
+ //
328
+ // To split around the first instance of a separator, see [Cut].
329
+ export function Split(s: $.Bytes, sep: $.Bytes): $.Slice<$.Bytes> {
330
+ return genSplit(s, sep, 0, -1)
331
+ }
332
+
333
+ // SplitAfter slices s into all subslices after each instance of sep and
334
+ // returns a slice of those subslices.
335
+ // If sep is empty, SplitAfter splits after each UTF-8 sequence.
336
+ // It is equivalent to SplitAfterN with a count of -1.
337
+ export function SplitAfter(s: $.Bytes, sep: $.Bytes): $.Slice<$.Bytes> {
338
+ return genSplit(s, sep, $.len(sep), -1)
339
+ }
340
+
341
+ export let asciiSpace = $.arrayToSlice<number>([0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
342
+
343
+ // Fields interprets s as a sequence of UTF-8-encoded code points.
344
+ // It splits the slice s around each instance of one or more consecutive white space
345
+ // characters, as defined by [unicode.IsSpace], returning a slice of subslices of s or an
346
+ // empty slice if s contains only white space.
347
+ export function Fields(s: $.Bytes): $.Slice<$.Bytes> {
348
+ // Use FieldsFunc with unicode.IsSpace
349
+ return FieldsFunc(s, unicode.IsSpace)
350
+ }
351
+
352
+ // FieldsFunc interprets s as a sequence of UTF-8-encoded code points.
353
+ // It splits the slice s at each run of code points c satisfying f(c) and
354
+ // returns a slice of subslices of s. If all code points in s satisfy f(c), or
355
+ // len(s) == 0, an empty slice is returned.
356
+ //
357
+ // FieldsFunc makes no guarantees about the order in which it calls f(c)
358
+ // and assumes that f always returns the same value for a given c.
359
+ export function FieldsFunc(s: $.Bytes, f: ((p0: number) => boolean) | null): $.Slice<$.Bytes> {
360
+ if (s === null || f === null) {
361
+ return null
362
+ }
363
+
364
+ const result: $.Bytes[] = []
365
+ let start = -1
366
+
367
+ for (let i = 0; i < $.len(s); ) {
368
+ let size = 1
369
+ let r = s![i]
370
+
371
+ if (r >= utf8.RuneSelf) {
372
+ const [rune, runeSize] = utf8.DecodeRune($.goSlice(s, i, undefined))
373
+ r = rune
374
+ size = runeSize
375
+ }
376
+
377
+ if (f(r)) {
378
+ // Found separator
379
+ if (start >= 0) {
380
+ result.push($.goSlice(s, start, i))
381
+ start = -1
382
+ }
383
+ } else if (start < 0) {
384
+ // Start of new field
385
+ start = i
386
+ }
387
+
388
+ i += size
389
+ }
390
+
391
+ // Add final field if any
392
+ if (start >= 0) {
393
+ result.push($.goSlice(s, start, undefined))
394
+ }
395
+
396
+ return result.length === 0 ? null : $.arrayToSlice(result)
397
+ }
398
+
399
+ // Join concatenates the elements of s to create a new byte slice. The separator
400
+ // sep is placed between elements in the resulting slice.
401
+ export function Join(s: $.Slice<$.Bytes>, sep: $.Bytes): $.Bytes {
402
+ if (s === null || $.len(s) === 0) {
403
+ return new Uint8Array(0)
404
+ }
405
+
406
+ // Just return a copy for single element
407
+ if ($.len(s) === 1) {
408
+ if (s![0] === null) return new Uint8Array(0)
409
+ return new Uint8Array($.bytesToArray(s![0]))
410
+ }
411
+
412
+ // Calculate total length needed
413
+ let totalLen = 0
414
+ const sepLen = sep === null ? 0 : $.len(sep)
415
+
416
+ for (let i = 0; i < $.len(s); i++) {
417
+ const elem = s![i]
418
+ if (elem !== null) {
419
+ totalLen += $.len(elem)
420
+ }
421
+ }
422
+
423
+ if (sepLen > 0) {
424
+ totalLen += sepLen * ($.len(s) - 1)
425
+ }
426
+
427
+ // Build result
428
+ const result = new Uint8Array(totalLen)
429
+ let pos = 0
430
+
431
+ for (let i = 0; i < $.len(s); i++) {
432
+ if (i > 0 && sepLen > 0) {
433
+ const sepArr = $.bytesToArray(sep)
434
+ for (let j = 0; j < sepArr.length; j++) {
435
+ result[pos++] = sepArr[j]
436
+ }
437
+ }
438
+
439
+ const elem = s![i]
440
+ if (elem !== null) {
441
+ const elemArr = $.bytesToArray(elem)
442
+ for (let j = 0; j < elemArr.length; j++) {
443
+ result[pos++] = elemArr[j]
444
+ }
445
+ }
446
+ }
447
+
448
+ return result
449
+ }
450
+
451
+ // HasPrefix reports whether the byte slice s begins with prefix.
452
+ export function HasPrefix(s: $.Bytes, prefix: $.Bytes): boolean {
453
+ if (s === null) s = new Uint8Array(0)
454
+ if (prefix === null) prefix = new Uint8Array(0)
455
+
456
+ if ($.len(s) < $.len(prefix)) return false
457
+
458
+ const sArr = $.bytesToArray(s)
459
+ const prefixArr = $.bytesToArray(prefix)
460
+
461
+ for (let i = 0; i < prefixArr.length; i++) {
462
+ if (sArr[i] !== prefixArr[i]) return false
463
+ }
464
+
465
+ return true
466
+ }
467
+
468
+ // HasSuffix reports whether the byte slice s ends with suffix.
469
+ export function HasSuffix(s: $.Bytes, suffix: $.Bytes): boolean {
470
+ if (s === null) s = new Uint8Array(0)
471
+ if (suffix === null) suffix = new Uint8Array(0)
472
+
473
+ if ($.len(s) < $.len(suffix)) return false
474
+
475
+ const sArr = $.bytesToArray(s)
476
+ const suffixArr = $.bytesToArray(suffix)
477
+ const offset = sArr.length - suffixArr.length
478
+
479
+ for (let i = 0; i < suffixArr.length; i++) {
480
+ if (sArr[offset + i] !== suffixArr[i]) return false
481
+ }
482
+
483
+ return true
484
+ }
485
+
486
+ // Map returns a copy of the byte slice s with all its characters modified
487
+ // according to the mapping function. If mapping returns a negative value, the character is
488
+ // dropped from the byte slice with no replacement. The characters in s and the
489
+ // output are interpreted as UTF-8-encoded code points.
490
+ export function Map(mapping: ((r: number) => number) | null, s: $.Bytes): $.Bytes {
491
+ if (s === null || $.len(s) === 0 || mapping === null) {
492
+ return s === null ? null : new Uint8Array(0)
493
+ }
494
+
495
+ const result: number[] = []
496
+
497
+ for (let i = 0; i < $.len(s); ) {
498
+ const [r, size] = utf8.DecodeRune($.goSlice(s, i, undefined))
499
+ if (size <= 0) {
500
+ // Invalid UTF-8, copy the byte as-is
501
+ result.push(s![i])
502
+ i++
503
+ } else {
504
+ const mappedR = mapping(r)
505
+ if (mappedR >= 0) {
506
+ // Encode the mapped rune back to bytes
507
+ const runeBytes = new Uint8Array(utf8.UTFMax)
508
+ const n = utf8.EncodeRune(runeBytes, mappedR)
509
+
510
+ // Add the encoded bytes to result
511
+ for (let j = 0; j < n; j++) {
512
+ result.push(runeBytes[j])
513
+ }
514
+ }
515
+
516
+ i += size
517
+ }
518
+ }
519
+
520
+ return new Uint8Array(result)
521
+ }
522
+
523
+ // Repeat returns a new byte slice consisting of count copies of b.
524
+ //
525
+ // It panics if count is negative or if the result of (len(b) * count)
526
+ // overflows.
527
+ export function Repeat(b: $.Bytes, count: number): $.Bytes {
528
+ if (count === 0) {
529
+ return new Uint8Array(0)
530
+ }
531
+
532
+ if (count < 0) {
533
+ $.panic("bytes: negative Repeat count")
534
+ }
535
+
536
+ if (b === null || $.len(b) === 0) {
537
+ return new Uint8Array(0)
538
+ }
539
+
540
+ const bArr = $.bytesToArray(b)
541
+ const totalLen = bArr.length * count
542
+
543
+ // Check for overflow
544
+ if (totalLen / count !== bArr.length) {
545
+ $.panic("bytes: Repeat output length overflow")
546
+ }
547
+
548
+ const result = new Uint8Array(totalLen)
549
+ let pos = 0
550
+
551
+ for (let i = 0; i < count; i++) {
552
+ for (let j = 0; j < bArr.length; j++) {
553
+ result[pos++] = bArr[j]
554
+ }
555
+ }
556
+
557
+ return result
558
+ }
559
+
560
+ // ToUpper returns a copy of the byte slice s with all Unicode letters mapped to
561
+ // their upper case.
562
+ export function ToUpper(s: $.Bytes): $.Bytes {
563
+ if (s === null || $.len(s) === 0) {
564
+ return new Uint8Array(0)
565
+ }
566
+
567
+ const result: number[] = []
568
+
569
+ for (let i = 0; i < $.len(s); ) {
570
+ const [r, size] = utf8.DecodeRune($.goSlice(s, i, undefined))
571
+ if (size <= 0) {
572
+ // Invalid UTF-8, copy the byte as-is
573
+ result.push(s![i])
574
+ i++
575
+ } else {
576
+ // Convert rune to uppercase
577
+ const upperR = unicode.ToUpper(r)
578
+
579
+ // Encode the uppercase rune back to bytes
580
+ const runeBytes = new Uint8Array(utf8.UTFMax)
581
+ const n = utf8.EncodeRune(runeBytes, upperR)
582
+
583
+ // Add the encoded bytes to result
584
+ for (let j = 0; j < n; j++) {
585
+ result.push(runeBytes[j])
586
+ }
587
+
588
+ i += size
589
+ }
590
+ }
591
+
592
+ return new Uint8Array(result)
593
+ }
594
+
595
+ // ToLower returns a copy of the byte slice s with all Unicode letters mapped to
596
+ // their lower case.
597
+ export function ToLower(s: $.Bytes): $.Bytes {
598
+ if (s === null || $.len(s) === 0) {
599
+ return new Uint8Array(0)
600
+ }
601
+
602
+ const result: number[] = []
603
+
604
+ for (let i = 0; i < $.len(s); ) {
605
+ const [r, size] = utf8.DecodeRune($.goSlice(s, i, undefined))
606
+ if (size <= 0) {
607
+ // Invalid UTF-8, copy the byte as-is
608
+ result.push(s![i])
609
+ i++
610
+ } else {
611
+ // Convert rune to lowercase
612
+ const lowerR = unicode.ToLower(r)
613
+
614
+ // Encode the lowercase rune back to bytes
615
+ const runeBytes = new Uint8Array(utf8.UTFMax)
616
+ const n = utf8.EncodeRune(runeBytes, lowerR)
617
+
618
+ // Add the encoded bytes to result
619
+ for (let j = 0; j < n; j++) {
620
+ result.push(runeBytes[j])
621
+ }
622
+
623
+ i += size
624
+ }
625
+ }
626
+
627
+ return new Uint8Array(result)
628
+ }
629
+
630
+ // ToTitle treats s as UTF-8-encoded bytes and returns a copy with all the Unicode letters mapped to their title case.
631
+ export function ToTitle(s: $.Bytes): $.Bytes {
632
+ return Map(unicode.ToTitle, s)
633
+ }
634
+
635
+ // ToUpperSpecial treats s as UTF-8-encoded bytes and returns a copy with all the Unicode letters mapped to their
636
+ // upper case, giving priority to the special casing rules.
637
+ export function ToUpperSpecial(c: unicode.SpecialCase, s: $.Bytes): $.Bytes {
638
+ // For now, ignore special case and fall back to regular ToUpper
639
+ return ToUpper(s)
640
+ }
641
+
642
+ // ToLowerSpecial treats s as UTF-8-encoded bytes and returns a copy with all the Unicode letters mapped to their
643
+ // lower case, giving priority to the special casing rules.
644
+ export function ToLowerSpecial(c: unicode.SpecialCase, s: $.Bytes): $.Bytes {
645
+ // For now, ignore special case and fall back to regular ToLower
646
+ return ToLower(s)
647
+ }
648
+
649
+ // ToTitleSpecial treats s as UTF-8-encoded bytes and returns a copy with all the Unicode letters mapped to their
650
+ // title case, giving priority to the special casing rules.
651
+ export function ToTitleSpecial(c: unicode.SpecialCase, s: $.Bytes): $.Bytes {
652
+ // For now, ignore special case and fall back to regular ToTitle
653
+ return ToTitle(s)
654
+ }
655
+
656
+ // ToValidUTF8 treats s as UTF-8-encoded bytes and returns a copy with each run of bytes
657
+ // representing invalid UTF-8 replaced with the bytes in replacement, which may be empty.
658
+ export function ToValidUTF8(s: $.Bytes, replacement: $.Bytes): $.Bytes {
659
+ if (s === null || $.len(s) === 0) {
660
+ return s === null ? null : new Uint8Array(0)
661
+ }
662
+
663
+ const result: number[] = []
664
+ const replacementArr = replacement ? $.bytesToArray(replacement) : []
665
+
666
+ for (let i = 0; i < $.len(s); ) {
667
+ const [r, size] = utf8.DecodeRune($.goSlice(s, i, undefined))
668
+ if (size <= 0 || r === utf8.RuneError) {
669
+ // Invalid UTF-8, replace with replacement bytes
670
+ for (const b of replacementArr) {
671
+ result.push(b)
672
+ }
673
+ i++
674
+ } else {
675
+ for (let j = 0; j < size; j++) {
676
+ result.push(s![i + j])
677
+ }
678
+ i += size
679
+ }
680
+ }
681
+
682
+ return new Uint8Array(result)
683
+ }
684
+
685
+ // isSeparator reports whether the rune could mark a word boundary.
686
+ // TODO: update when package unicode captures more of the properties.
687
+ export function isSeparator(r: number): boolean {
688
+ // ASCII alphanumerics and underscore are not separators
689
+ if (r <= 0x7F) {
690
+ if ((48 <= r && r <= 57) || // 0-9
691
+ (97 <= r && r <= 122) || // a-z
692
+ (65 <= r && r <= 90) || // A-Z
693
+ r === 95) { // _
694
+ return false
695
+ }
696
+ return true
697
+ }
698
+ // Letters and digits are not separators
699
+ if (unicode.IsLetter(r) || unicode.IsDigit(r)) {
700
+ return false
701
+ }
702
+ // Otherwise, all we can do for now is treat spaces as separators.
703
+ return unicode.IsSpace(r)
704
+ }
705
+
706
+ // Title treats s as UTF-8-encoded bytes and returns a copy with all Unicode letters that begin
707
+ // words mapped to their title case.
708
+ //
709
+ // Deprecated: The rule Title uses for word boundaries does not handle Unicode
710
+ // punctuation properly. Use golang.org/x/text/cases instead.
711
+ export function Title(s: $.Bytes): $.Bytes {
712
+ if (s === null || $.len(s) === 0) {
713
+ return s === null ? null : new Uint8Array(0)
714
+ }
715
+
716
+ const result: number[] = []
717
+ let prevIsSep = true // Start of string counts as separator
718
+
719
+ for (let i = 0; i < $.len(s); ) {
720
+ const [r, size] = utf8.DecodeRune($.goSlice(s, i, undefined))
721
+ if (size <= 0) {
722
+ // Invalid UTF-8, copy the byte as-is
723
+ result.push(s![i])
724
+ i++
725
+ prevIsSep = true
726
+ } else {
727
+ let transformedR = r
728
+ if (prevIsSep && unicode.IsLetter(r)) {
729
+ transformedR = unicode.ToTitle(r)
730
+ }
731
+
732
+ // Encode the (possibly transformed) rune back to bytes
733
+ const runeBytes = new Uint8Array(utf8.UTFMax)
734
+ const n = utf8.EncodeRune(runeBytes, transformedR)
735
+
736
+ // Add the encoded bytes to result
737
+ for (let j = 0; j < n; j++) {
738
+ result.push(runeBytes[j])
739
+ }
740
+
741
+ prevIsSep = isSeparator(r)
742
+ i += size
743
+ }
744
+ }
745
+
746
+ return new Uint8Array(result)
747
+ }
748
+
749
+ // TrimLeftFunc treats s as UTF-8-encoded bytes and returns a subslice of s by slicing off
750
+ // all leading UTF-8-encoded code points c that satisfy f(c).
751
+ export function TrimLeftFunc(s: $.Bytes, f: ((r: number) => boolean) | null): $.Bytes {
752
+ const i = indexFunc(s, f, false)
753
+ if (i === -1) {
754
+ return null
755
+ }
756
+ return $.goSlice(s, i, undefined)
757
+ }
758
+
759
+ // TrimRightFunc returns a subslice of s by slicing off all trailing
760
+ // UTF-8-encoded code points c that satisfy f(c).
761
+ export function TrimRightFunc(s: $.Bytes, f: ((r: number) => boolean) | null): $.Bytes {
762
+ const i = lastIndexFunc(s, f, false)
763
+ if (i >= 0 && $.len(s) > i) {
764
+ const [, wid] = utf8.DecodeRune($.goSlice(s, i, undefined))
765
+ return $.goSlice(s, undefined, i + wid)
766
+ }
767
+ return null
768
+ }
769
+
770
+ // TrimFunc returns a subslice of s by slicing off all leading and trailing
771
+ // UTF-8-encoded code points c that satisfy f(c).
772
+ export function TrimFunc(s: $.Bytes, f: ((r: number) => boolean) | null): $.Bytes {
773
+ return TrimRightFunc(TrimLeftFunc(s, f), f)
774
+ }
775
+
776
+ // TrimPrefix returns s without the provided leading prefix string.
777
+ // If s doesn't start with prefix, s is returned unchanged.
778
+ export function TrimPrefix(s: $.Bytes, prefix: $.Bytes): $.Bytes {
779
+ if (HasPrefix(s, prefix)) {
780
+ return $.goSlice(s, $.len(prefix), undefined)
781
+ }
782
+ return s
783
+ }
784
+
785
+ // TrimSuffix returns s without the provided trailing suffix string.
786
+ // If s doesn't end with suffix, s is returned unchanged.
787
+ export function TrimSuffix(s: $.Bytes, suffix: $.Bytes): $.Bytes {
788
+ if (HasSuffix(s, suffix)) {
789
+ return $.goSlice(s, undefined, $.len(s) - $.len(suffix))
790
+ }
791
+ return s
792
+ }
793
+
794
+ // IndexFunc interprets s as a sequence of UTF-8-encoded code points.
795
+ // It returns the byte index in s of the first Unicode
796
+ // code point satisfying f(c), or -1 if none do.
797
+ export function IndexFunc(s: $.Bytes, f: ((r: number) => boolean) | null): number {
798
+ return indexFunc(s, f, true)
799
+ }
800
+
801
+ // LastIndexFunc interprets s as a sequence of UTF-8-encoded code points.
802
+ // It returns the byte index in s of the last Unicode
803
+ // code point satisfying f(c), or -1 if none do.
804
+ export function LastIndexFunc(s: $.Bytes, f: ((r: number) => boolean) | null): number {
805
+ return lastIndexFunc(s, f, true)
806
+ }
807
+
808
+ // indexFunc is the same as IndexFunc except that if
809
+ // truth==false, the sense of the predicate function is
810
+ // inverted.
811
+ export function indexFunc(s: $.Bytes, f: ((r: number) => boolean) | null, truth: boolean): number {
812
+ if (s === null || f === null) {
813
+ return -1
814
+ }
815
+
816
+ for (let i = 0; i < $.len(s); ) {
817
+ const [r, size] = utf8.DecodeRune($.goSlice(s, i, undefined))
818
+ if (size <= 0) {
819
+ // Invalid UTF-8
820
+ if (f(utf8.RuneError) === truth) {
821
+ return i
822
+ }
823
+ i++
824
+ } else {
825
+ if (f(r) === truth) {
826
+ return i
827
+ }
828
+ i += size
829
+ }
830
+ }
831
+
832
+ return -1
833
+ }
834
+
835
+ // lastIndexFunc is the same as LastIndexFunc except that if
836
+ // truth==false, the sense of the predicate function is
837
+ // inverted.
838
+ export function lastIndexFunc(s: $.Bytes, f: ((r: number) => boolean) | null, truth: boolean): number {
839
+ if (s === null || f === null) {
840
+ return -1
841
+ }
842
+
843
+ let lastIndex = -1
844
+
845
+ for (let i = 0; i < $.len(s); ) {
846
+ const [r, size] = utf8.DecodeRune($.goSlice(s, i, undefined))
847
+ if (size <= 0) {
848
+ // Invalid UTF-8
849
+ if (f(utf8.RuneError) === truth) {
850
+ lastIndex = i
851
+ }
852
+ i++
853
+ } else {
854
+ if (f(r) === truth) {
855
+ lastIndex = i
856
+ }
857
+ i += size
858
+ }
859
+ }
860
+
861
+ return lastIndex
862
+ }
863
+
864
+ class asciiSet {
865
+ constructor(public _value: number[]) {}
866
+
867
+ valueOf(): number[] {
868
+ return this._value
869
+ }
870
+
871
+ toString(): string {
872
+ return String(this._value)
873
+ }
874
+
875
+ static from(value: number[]): asciiSet {
876
+ return new asciiSet(value)
877
+ }
878
+
879
+ // contains reports whether c is inside the set.
880
+ public contains(c: number): boolean {
881
+ const _as = this._value
882
+ return ((_as![c >> 5] & (1 << (c & 31)))) !== 0
883
+ }
884
+ }
885
+
886
+ // makeASCIISet creates a set of ASCII characters and reports whether all
887
+ // characters in chars are ASCII.
888
+ export function makeASCIISet(chars: string): [asciiSet, boolean] {
889
+ const _as = new asciiSet([0, 0, 0, 0, 0, 0, 0, 0])
890
+
891
+ for (let i = 0; i < chars.length; i++) {
892
+ const c = chars.charCodeAt(i)
893
+ if (c >= utf8.RuneSelf) {
894
+ return [_as, false]
895
+ }
896
+ _as._value[c >> 5] |= (1 << (c & 31))
897
+ }
898
+
899
+ return [_as, true]
900
+ }
901
+
902
+ // containsRune is a simplified version of strings.ContainsRune
903
+ // to avoid importing the strings package.
904
+ // We avoid bytes.ContainsRune to avoid allocating a temporary copy of s.
905
+ export function containsRune(s: string, r: number): boolean {
906
+ for (let i = 0; i < s.length; ) {
907
+ const c = s.codePointAt(i)
908
+ if (c === r) return true
909
+ i += c! > 0xFFFF ? 2 : 1
910
+ }
911
+ return false
912
+ }
913
+
914
+ // Trim returns a subslice of s by slicing off all leading and
915
+ // trailing UTF-8-encoded code points contained in cutset.
916
+ export function Trim(s: $.Bytes, cutset: string): $.Bytes {
917
+ if (s === null || cutset.length === 0) {
918
+ return s
919
+ }
920
+
921
+ if (cutset.length === 1 && cutset.charCodeAt(0) < utf8.RuneSelf) {
922
+ // Single ASCII character optimization
923
+ return trimRightByte(trimLeftByte(s, cutset.charCodeAt(0)), cutset.charCodeAt(0))
924
+ }
925
+
926
+ const [as, allASCII] = makeASCIISet(cutset)
927
+ if (allASCII) {
928
+ return trimRightASCII(trimLeftASCII(s, as), as)
929
+ }
930
+
931
+ return trimRightUnicode(trimLeftUnicode(s, cutset), cutset)
932
+ }
933
+
934
+ // TrimLeft returns a subslice of s by slicing off all leading
935
+ // UTF-8-encoded code points contained in cutset.
936
+ export function TrimLeft(s: $.Bytes, cutset: string): $.Bytes {
937
+ if (s === null || cutset.length === 0) {
938
+ return s
939
+ }
940
+
941
+ if (cutset.length === 1 && cutset.charCodeAt(0) < utf8.RuneSelf) {
942
+ // Single ASCII character optimization
943
+ return trimLeftByte(s, cutset.charCodeAt(0))
944
+ }
945
+
946
+ const [as, allASCII] = makeASCIISet(cutset)
947
+ if (allASCII) {
948
+ return trimLeftASCII(s, as)
949
+ }
950
+
951
+ return trimLeftUnicode(s, cutset)
952
+ }
953
+
954
+ export function trimLeftByte(s: $.Bytes, c: number): $.Bytes {
955
+ if (s === null) return null
956
+
957
+ for (let i = 0; i < $.len(s); i++) {
958
+ if (s![i] !== c) {
959
+ return $.goSlice(s, i, undefined)
960
+ }
961
+ }
962
+
963
+ return null
964
+ }
965
+
966
+ export function trimLeftASCII(s: $.Bytes, _as: asciiSet): $.Bytes {
967
+ if (s === null) return null
968
+
969
+ for (let i = 0; i < $.len(s); i++) {
970
+ const b = s![i]
971
+ if (b >= utf8.RuneSelf || !_as.contains(b)) {
972
+ return $.goSlice(s, i, undefined)
973
+ }
974
+ }
975
+
976
+ return null
977
+ }
978
+
979
+ export function trimLeftUnicode(s: $.Bytes, cutset: string): $.Bytes {
980
+ if (s === null) return null
981
+
982
+ for (let i = 0; i < $.len(s); ) {
983
+ const [r, size] = utf8.DecodeRune($.goSlice(s, i, undefined))
984
+ if (size <= 0) {
985
+ // Invalid UTF-8, keep it
986
+ return $.goSlice(s, i, undefined)
987
+ }
988
+
989
+ if (!containsRune(cutset, r)) {
990
+ return $.goSlice(s, i, undefined)
991
+ }
992
+
993
+ i += size
994
+ }
995
+
996
+ return null
997
+ }
998
+
999
+ // TrimRight returns a subslice of s by slicing off all trailing
1000
+ // UTF-8-encoded code points that are contained in cutset.
1001
+ export function TrimRight(s: $.Bytes, cutset: string): $.Bytes {
1002
+ if (s === null || cutset.length === 0) {
1003
+ return s
1004
+ }
1005
+
1006
+ if (cutset.length === 1 && cutset.charCodeAt(0) < utf8.RuneSelf) {
1007
+ // Single ASCII character optimization
1008
+ return trimRightByte(s, cutset.charCodeAt(0))
1009
+ }
1010
+
1011
+ const [as, allASCII] = makeASCIISet(cutset)
1012
+ if (allASCII) {
1013
+ return trimRightASCII(s, as)
1014
+ }
1015
+
1016
+ return trimRightUnicode(s, cutset)
1017
+ }
1018
+
1019
+ export function trimRightByte(s: $.Bytes, c: number): $.Bytes {
1020
+ if (s === null) return null
1021
+
1022
+ for (let i = $.len(s) - 1; i >= 0; i--) {
1023
+ if (s![i] !== c) {
1024
+ return $.goSlice(s, undefined, i + 1)
1025
+ }
1026
+ }
1027
+
1028
+ return null
1029
+ }
1030
+
1031
+ export function trimRightASCII(s: $.Bytes, _as: asciiSet): $.Bytes {
1032
+ if (s === null) return null
1033
+
1034
+ for (let i = $.len(s) - 1; i >= 0; i--) {
1035
+ const b = s![i]
1036
+ if (b >= utf8.RuneSelf || !_as.contains(b)) {
1037
+ return $.goSlice(s, undefined, i + 1)
1038
+ }
1039
+ }
1040
+
1041
+ return null
1042
+ }
1043
+
1044
+ export function trimRightUnicode(s: $.Bytes, cutset: string): $.Bytes {
1045
+ if (s === null) return null
1046
+
1047
+ // Need to scan from left to find rune boundaries, but track the last non-cutset position
1048
+ let lastKeep = -1
1049
+
1050
+ for (let i = 0; i < $.len(s); ) {
1051
+ const [r, size] = utf8.DecodeRune($.goSlice(s, i, undefined))
1052
+ if (size <= 0) {
1053
+ // Invalid UTF-8, keep everything up to here
1054
+ return $.goSlice(s, undefined, i + 1)
1055
+ }
1056
+
1057
+ if (!containsRune(cutset, r)) {
1058
+ lastKeep = i + size
1059
+ }
1060
+
1061
+ i += size
1062
+ }
1063
+
1064
+ if (lastKeep < 0) {
1065
+ return null
1066
+ }
1067
+
1068
+ return $.goSlice(s, undefined, lastKeep)
1069
+ }
1070
+
1071
+ // TrimSpace returns a subslice of s by slicing off all leading and
1072
+ // trailing white space, as defined by Unicode.
1073
+ export function TrimSpace(s: $.Bytes): $.Bytes {
1074
+ return TrimFunc(s, unicode.IsSpace)
1075
+ }
1076
+
1077
+ // Runes interprets s as a sequence of UTF-8-encoded code points.
1078
+ // It returns a slice of runes (Unicode code points) equivalent to s.
1079
+ export function Runes(s: $.Bytes): $.Slice<number> {
1080
+ if (s === null || $.len(s) === 0) {
1081
+ return null
1082
+ }
1083
+
1084
+ const result: number[] = []
1085
+
1086
+ for (let i = 0; i < $.len(s); ) {
1087
+ const [r, size] = utf8.DecodeRune($.goSlice(s, i, undefined))
1088
+ if (size <= 0) {
1089
+ // Invalid UTF-8, add replacement character
1090
+ result.push(utf8.RuneError)
1091
+ i++
1092
+ } else {
1093
+ result.push(r)
1094
+ i += size
1095
+ }
1096
+ }
1097
+
1098
+ return $.arrayToSlice(result)
1099
+ }
1100
+
1101
+ // Replace returns a copy of the slice s with the first n
1102
+ // non-overlapping instances of old replaced by new.
1103
+ // If old is empty, it matches at the beginning of the slice
1104
+ // and after each UTF-8 sequence, yielding up to k+1 replacements
1105
+ // for a k-rune slice.
1106
+ // If n < 0, there is no limit on the number of replacements.
1107
+ export function Replace(s: $.Bytes, old: $.Bytes, _new: $.Bytes, n: number): $.Bytes {
1108
+ if (s === null) {
1109
+ return new Uint8Array(0)
1110
+ }
1111
+
1112
+ if (n === 0) {
1113
+ // Make a copy without any replacements
1114
+ return new Uint8Array($.bytesToArray(s))
1115
+ }
1116
+
1117
+ // Handle empty old pattern - replace at beginning and after each UTF-8 sequence
1118
+ if (old === null || $.len(old) === 0) {
1119
+ const result: number[] = []
1120
+ const newBytes = _new === null ? [] : $.bytesToArray(_new)
1121
+
1122
+ // Add replacement at beginning
1123
+ if (n !== 0) {
1124
+ result.push(...newBytes)
1125
+ if (n > 0) n--
1126
+ }
1127
+
1128
+ // Add replacement after each UTF-8 sequence
1129
+ for (let i = 0; i < $.len(s) && n !== 0; ) {
1130
+ const [, size] = utf8.DecodeRune($.goSlice(s, i, undefined))
1131
+ if (size <= 0) {
1132
+ result.push(s![i])
1133
+ i++
1134
+ } else {
1135
+ // Add the rune bytes
1136
+ for (let j = 0; j < size; j++) {
1137
+ result.push(s![i + j])
1138
+ }
1139
+ i += size
1140
+ }
1141
+
1142
+ // Add replacement after this rune
1143
+ if (n !== 0) {
1144
+ result.push(...newBytes)
1145
+ if (n > 0) n--
1146
+ }
1147
+ }
1148
+
1149
+ return new Uint8Array(result)
1150
+ }
1151
+
1152
+ // Normal case - replace occurrences of old with new
1153
+ const result: number[] = []
1154
+ const sBytes = $.bytesToArray(s)
1155
+ const oldBytes = $.bytesToArray(old)
1156
+ const newBytes = _new === null ? [] : $.bytesToArray(_new)
1157
+
1158
+ let i = 0
1159
+ let replacements = 0
1160
+
1161
+ while (i <= sBytes.length - oldBytes.length && (n < 0 || replacements < n)) {
1162
+ // Check if old pattern matches at current position
1163
+ let matches = true
1164
+ for (let j = 0; j < oldBytes.length; j++) {
1165
+ if (sBytes[i + j] !== oldBytes[j]) {
1166
+ matches = false
1167
+ break
1168
+ }
1169
+ }
1170
+
1171
+ if (matches) {
1172
+ // Replace with new bytes
1173
+ result.push(...newBytes)
1174
+ i += oldBytes.length
1175
+ replacements++
1176
+ } else {
1177
+ // Copy one byte and advance
1178
+ result.push(sBytes[i])
1179
+ i++
1180
+ }
1181
+ }
1182
+
1183
+ // Copy remaining bytes
1184
+ while (i < sBytes.length) {
1185
+ result.push(sBytes[i])
1186
+ i++
1187
+ }
1188
+
1189
+ return new Uint8Array(result)
1190
+ }
1191
+
1192
+ // ReplaceAll returns a copy of the slice s with all
1193
+ // non-overlapping instances of old replaced by new.
1194
+ // If old is empty, it matches at the beginning of the slice
1195
+ // and after each UTF-8 sequence, yielding up to k+1 replacements
1196
+ // for a k-rune slice.
1197
+ export function ReplaceAll(s: $.Bytes, old: $.Bytes, _new: $.Bytes): $.Bytes {
1198
+ return Replace(s, old, _new, -1)
1199
+ }
1200
+
1201
+ // EqualFold reports whether s and t, interpreted as UTF-8 strings,
1202
+ // are equal under simple Unicode case-folding, which is a more general
1203
+ // form of case-insensitivity.
1204
+ export function EqualFold(s: $.Bytes, t: $.Bytes): boolean {
1205
+ if (s === null && t === null) return true
1206
+ if (s === null || t === null) return false
1207
+
1208
+ let si = 0, ti = 0
1209
+
1210
+ while (si < $.len(s) && ti < $.len(t)) {
1211
+ const [sr, ssize] = utf8.DecodeRune($.goSlice(s, si, undefined))
1212
+ const [tr, tsize] = utf8.DecodeRune($.goSlice(t, ti, undefined))
1213
+
1214
+ if (ssize <= 0 || tsize <= 0) {
1215
+ // Invalid UTF-8, fall back to byte comparison
1216
+ if (s![si] !== t![ti]) return false
1217
+ si++
1218
+ ti++
1219
+ } else {
1220
+ // Convert both to lowercase for comparison
1221
+ const sLower = unicode.ToLower(sr)
1222
+ const tLower = unicode.ToLower(tr)
1223
+
1224
+ if (sLower !== tLower) return false
1225
+
1226
+ si += ssize
1227
+ ti += tsize
1228
+ }
1229
+ }
1230
+
1231
+ return si === $.len(s) && ti === $.len(t)
1232
+ }
1233
+
1234
+ // Index returns the index of the first instance of sep in s, or -1 if sep is not present in s.
1235
+ export function Index(s: $.Bytes, sep: $.Bytes): number {
1236
+ return $.bytesIndexOf(s, sep)
1237
+ }
1238
+
1239
+ // Cut slices s around the first instance of sep,
1240
+ // returning the text before and after sep.
1241
+ // The found result reports whether sep appears in s.
1242
+ // If sep does not appear in s, cut returns s, nil, false.
1243
+ //
1244
+ // Cut returns slices of the original slice s, not copies.
1245
+ export function Cut(s: $.Bytes, sep: $.Bytes): [$.Bytes, $.Bytes, boolean] {
1246
+ const i = Index(s, sep)
1247
+ if (i >= 0) {
1248
+ return [$.goSlice(s, undefined, i), $.goSlice(s, i + $.len(sep), undefined), true]
1249
+ }
1250
+ return [s, null, false]
1251
+ }
1252
+
1253
+ // Clone returns a copy of b[:len(b)].
1254
+ // The result may have additional unused capacity.
1255
+ // Clone(nil) returns nil.
1256
+ export function Clone(b: $.Bytes): $.Bytes {
1257
+ if (b === null) {
1258
+ return null
1259
+ }
1260
+ return new Uint8Array($.bytesToArray(b))
1261
+ }
1262
+
1263
+ // CutPrefix returns s without the provided leading prefix byte slice
1264
+ // and reports whether it found the prefix.
1265
+ // If s doesn't start with prefix, CutPrefix returns s, false.
1266
+ // If prefix is the empty byte slice, CutPrefix returns s, true.
1267
+ //
1268
+ // CutPrefix returns slices of the original slice s, not copies.
1269
+ export function CutPrefix(s: $.Bytes, prefix: $.Bytes): [$.Bytes, boolean] {
1270
+ if (!HasPrefix(s, prefix)) {
1271
+ return [s, false]
1272
+ }
1273
+ return [$.goSlice(s, $.len(prefix), undefined), true]
1274
+ }
1275
+
1276
+ // CutSuffix returns s without the provided ending suffix byte slice
1277
+ // and reports whether it found the suffix.
1278
+ // If s doesn't end with suffix, CutSuffix returns s, false.
1279
+ // If suffix is the empty byte slice, CutSuffix returns s, true.
1280
+ //
1281
+ // CutSuffix returns slices of the original slice s, not copies.
1282
+ export function CutSuffix(s: $.Bytes, suffix: $.Bytes): [$.Bytes, boolean] {
1283
+ if (!HasSuffix(s, suffix)) {
1284
+ return [s, false]
1285
+ }
1286
+ return [$.goSlice(s, undefined, $.len(s) - $.len(suffix)), true]
1287
+ }
1288
+