goscript 0.0.38 → 0.0.39

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 (116) hide show
  1. package/compiler/expr-call.go +12 -0
  2. package/compiler/lit.go +17 -6
  3. package/dist/gs/builtin/builtin.d.ts +45 -0
  4. package/dist/gs/builtin/builtin.js +197 -0
  5. package/dist/gs/builtin/builtin.js.map +1 -1
  6. package/dist/gs/bytes/buffer.gs.d.ts +56 -0
  7. package/dist/gs/bytes/buffer.gs.js +611 -0
  8. package/dist/gs/bytes/buffer.gs.js.map +1 -0
  9. package/dist/gs/bytes/bytes.gs.d.ts +78 -0
  10. package/dist/gs/bytes/bytes.gs.js +1011 -0
  11. package/dist/gs/bytes/bytes.gs.js.map +1 -0
  12. package/dist/gs/bytes/index.d.ts +4 -0
  13. package/dist/gs/bytes/index.js +5 -0
  14. package/dist/gs/bytes/index.js.map +1 -0
  15. package/dist/gs/bytes/iter.gs.d.ts +9 -0
  16. package/dist/gs/bytes/iter.gs.js +143 -0
  17. package/dist/gs/bytes/iter.gs.js.map +1 -0
  18. package/dist/gs/bytes/reader.gs.d.ts +34 -0
  19. package/dist/gs/bytes/reader.gs.js +198 -0
  20. package/dist/gs/bytes/reader.gs.js.map +1 -0
  21. package/dist/gs/internal/bytealg/index.d.ts +14 -2
  22. package/dist/gs/internal/bytealg/index.js +114 -8
  23. package/dist/gs/internal/bytealg/index.js.map +1 -1
  24. package/dist/gs/reflect/deepequal.d.ts +2 -1
  25. package/dist/gs/reflect/deepequal.js +5 -53
  26. package/dist/gs/reflect/deepequal.js.map +1 -1
  27. package/dist/gs/reflect/map.d.ts +14 -8
  28. package/dist/gs/reflect/map.js +15 -11
  29. package/dist/gs/reflect/map.js.map +1 -1
  30. package/dist/gs/reflect/type.d.ts +17 -9
  31. package/dist/gs/reflect/type.js +1 -1
  32. package/dist/gs/reflect/type.js.map +1 -1
  33. package/dist/gs/reflect/value.js +2 -1
  34. package/dist/gs/reflect/value.js.map +1 -1
  35. package/dist/gs/reflect/visiblefields.js +18 -12
  36. package/dist/gs/reflect/visiblefields.js.map +1 -1
  37. package/dist/gs/unicode/utf8/utf8.d.ts +1 -1
  38. package/dist/gs/unicode/utf8/utf8.js +4 -2
  39. package/dist/gs/unicode/utf8/utf8.js.map +1 -1
  40. package/gs/builtin/builtin.ts +219 -0
  41. package/gs/bytes/buffer.gs.ts +614 -0
  42. package/gs/bytes/bytes.gs.ts +1180 -0
  43. package/gs/bytes/godoc.txt +69 -0
  44. package/gs/bytes/index.ts +69 -0
  45. package/gs/bytes/iter.gs.ts +149 -0
  46. package/gs/bytes/reader.gs.ts +230 -0
  47. package/gs/internal/bytealg/index.ts +125 -10
  48. package/gs/reflect/deepequal.test.ts +41 -0
  49. package/gs/reflect/deepequal.ts +19 -4
  50. package/gs/reflect/map.test.ts +30 -0
  51. package/gs/reflect/map.ts +22 -18
  52. package/gs/reflect/type.ts +19 -15
  53. package/gs/reflect/value.ts +8 -2
  54. package/gs/reflect/visiblefields.ts +17 -13
  55. package/gs/unicode/utf8/utf8.ts +8 -5
  56. package/package.json +1 -1
  57. package/dist/gs/internal/testlog/index.d.ts +0 -1
  58. package/dist/gs/internal/testlog/index.js +0 -5
  59. package/dist/gs/internal/testlog/index.js.map +0 -1
  60. package/dist/gs/maps/iter.gs.d.ts +0 -7
  61. package/dist/gs/maps/iter.gs.js +0 -65
  62. package/dist/gs/maps/iter.gs.js.map +0 -1
  63. package/dist/gs/maps/maps.gs.d.ts +0 -7
  64. package/dist/gs/maps/maps.gs.js +0 -79
  65. package/dist/gs/maps/maps.gs.js.map +0 -1
  66. package/dist/gs/reflect/abi.d.ts +0 -59
  67. package/dist/gs/reflect/abi.gs.d.ts +0 -59
  68. package/dist/gs/reflect/abi.gs.js +0 -79
  69. package/dist/gs/reflect/abi.gs.js.map +0 -1
  70. package/dist/gs/reflect/abi.js +0 -79
  71. package/dist/gs/reflect/abi.js.map +0 -1
  72. package/dist/gs/reflect/badlinkname.d.ts +0 -52
  73. package/dist/gs/reflect/badlinkname.gs.d.ts +0 -52
  74. package/dist/gs/reflect/badlinkname.gs.js +0 -72
  75. package/dist/gs/reflect/badlinkname.gs.js.map +0 -1
  76. package/dist/gs/reflect/badlinkname.js +0 -72
  77. package/dist/gs/reflect/badlinkname.js.map +0 -1
  78. package/dist/gs/reflect/deepequal.gs.d.ts +0 -25
  79. package/dist/gs/reflect/deepequal.gs.js +0 -308
  80. package/dist/gs/reflect/deepequal.gs.js.map +0 -1
  81. package/dist/gs/reflect/float32reg_generic.gs.d.ts +0 -2
  82. package/dist/gs/reflect/float32reg_generic.gs.js +0 -10
  83. package/dist/gs/reflect/float32reg_generic.gs.js.map +0 -1
  84. package/dist/gs/reflect/index.gs.d.ts +0 -1
  85. package/dist/gs/reflect/index.gs.js +0 -3
  86. package/dist/gs/reflect/index.gs.js.map +0 -1
  87. package/dist/gs/reflect/iter.gs.d.ts +0 -3
  88. package/dist/gs/reflect/iter.gs.js +0 -24
  89. package/dist/gs/reflect/iter.gs.js.map +0 -1
  90. package/dist/gs/reflect/makefunc.gs.d.ts +0 -34
  91. package/dist/gs/reflect/makefunc.gs.js +0 -288
  92. package/dist/gs/reflect/makefunc.gs.js.map +0 -1
  93. package/dist/gs/reflect/map_swiss.gs.d.ts +0 -14
  94. package/dist/gs/reflect/map_swiss.gs.js +0 -70
  95. package/dist/gs/reflect/map_swiss.gs.js.map +0 -1
  96. package/dist/gs/reflect/reflect.gs.d.ts +0 -132
  97. package/dist/gs/reflect/reflect.gs.js +0 -437
  98. package/dist/gs/reflect/reflect.gs.js.map +0 -1
  99. package/dist/gs/reflect/swapper.gs.d.ts +0 -1
  100. package/dist/gs/reflect/swapper.gs.js +0 -32
  101. package/dist/gs/reflect/swapper.gs.js.map +0 -1
  102. package/dist/gs/reflect/type.gs.d.ts +0 -4
  103. package/dist/gs/reflect/type.gs.js +0 -21
  104. package/dist/gs/reflect/type.gs.js.map +0 -1
  105. package/dist/gs/reflect/value.gs.d.ts +0 -4
  106. package/dist/gs/reflect/value.gs.js +0 -12
  107. package/dist/gs/reflect/value.gs.js.map +0 -1
  108. package/dist/gs/reflect/visiblefields.gs.d.ts +0 -3
  109. package/dist/gs/reflect/visiblefields.gs.js +0 -123
  110. package/dist/gs/reflect/visiblefields.gs.js.map +0 -1
  111. package/dist/gs/stringslite/index.d.ts +0 -1
  112. package/dist/gs/stringslite/index.js +0 -2
  113. package/dist/gs/stringslite/index.js.map +0 -1
  114. package/dist/gs/stringslite/strings.d.ts +0 -11
  115. package/dist/gs/stringslite/strings.js +0 -67
  116. package/dist/gs/stringslite/strings.js.map +0 -1
@@ -0,0 +1,1180 @@
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
+ // TODO: Implement Map function with proper UTF-8 handling
492
+ throw new Error("Map: not implemented")
493
+ }
494
+
495
+ // Repeat returns a new byte slice consisting of count copies of b.
496
+ //
497
+ // It panics if count is negative or if the result of (len(b) * count)
498
+ // overflows.
499
+ export function Repeat(b: $.Bytes, count: number): $.Bytes {
500
+ if (count === 0) {
501
+ return new Uint8Array(0)
502
+ }
503
+
504
+ if (count < 0) {
505
+ $.panic("bytes: negative Repeat count")
506
+ }
507
+
508
+ if (b === null || $.len(b) === 0) {
509
+ return new Uint8Array(0)
510
+ }
511
+
512
+ const bArr = $.bytesToArray(b)
513
+ const totalLen = bArr.length * count
514
+
515
+ // Check for overflow
516
+ if (totalLen / count !== bArr.length) {
517
+ $.panic("bytes: Repeat output length overflow")
518
+ }
519
+
520
+ const result = new Uint8Array(totalLen)
521
+ let pos = 0
522
+
523
+ for (let i = 0; i < count; i++) {
524
+ for (let j = 0; j < bArr.length; j++) {
525
+ result[pos++] = bArr[j]
526
+ }
527
+ }
528
+
529
+ return result
530
+ }
531
+
532
+ // ToUpper returns a copy of the byte slice s with all Unicode letters mapped to
533
+ // their upper case.
534
+ export function ToUpper(s: $.Bytes): $.Bytes {
535
+ if (s === null || $.len(s) === 0) {
536
+ return new Uint8Array(0)
537
+ }
538
+
539
+ const result: number[] = []
540
+
541
+ for (let i = 0; i < $.len(s); ) {
542
+ const [r, size] = utf8.DecodeRune($.goSlice(s, i, undefined))
543
+ if (size <= 0) {
544
+ // Invalid UTF-8, copy the byte as-is
545
+ result.push(s![i])
546
+ i++
547
+ } else {
548
+ // Convert rune to uppercase
549
+ const upperR = unicode.ToUpper(r)
550
+
551
+ // Encode the uppercase rune back to bytes
552
+ const runeBytes = new Uint8Array(utf8.UTFMax)
553
+ const n = utf8.EncodeRune(runeBytes, upperR)
554
+
555
+ // Add the encoded bytes to result
556
+ for (let j = 0; j < n; j++) {
557
+ result.push(runeBytes[j])
558
+ }
559
+
560
+ i += size
561
+ }
562
+ }
563
+
564
+ return new Uint8Array(result)
565
+ }
566
+
567
+ // ToLower returns a copy of the byte slice s with all Unicode letters mapped to
568
+ // their lower case.
569
+ export function ToLower(s: $.Bytes): $.Bytes {
570
+ if (s === null || $.len(s) === 0) {
571
+ return new Uint8Array(0)
572
+ }
573
+
574
+ const result: number[] = []
575
+
576
+ for (let i = 0; i < $.len(s); ) {
577
+ const [r, size] = utf8.DecodeRune($.goSlice(s, i, undefined))
578
+ if (size <= 0) {
579
+ // Invalid UTF-8, copy the byte as-is
580
+ result.push(s![i])
581
+ i++
582
+ } else {
583
+ // Convert rune to lowercase
584
+ const lowerR = unicode.ToLower(r)
585
+
586
+ // Encode the lowercase rune back to bytes
587
+ const runeBytes = new Uint8Array(utf8.UTFMax)
588
+ const n = utf8.EncodeRune(runeBytes, lowerR)
589
+
590
+ // Add the encoded bytes to result
591
+ for (let j = 0; j < n; j++) {
592
+ result.push(runeBytes[j])
593
+ }
594
+
595
+ i += size
596
+ }
597
+ }
598
+
599
+ return new Uint8Array(result)
600
+ }
601
+
602
+ // ToTitle treats s as UTF-8-encoded bytes and returns a copy with all the Unicode letters mapped to their title case.
603
+ export function ToTitle(s: $.Bytes): $.Bytes {
604
+ return Map(unicode.ToTitle, s)
605
+ }
606
+
607
+ // ToUpperSpecial treats s as UTF-8-encoded bytes and returns a copy with all the Unicode letters mapped to their
608
+ // upper case, giving priority to the special casing rules.
609
+ export function ToUpperSpecial(c: unicode.SpecialCase, s: $.Bytes): $.Bytes {
610
+ // TODO: Fix SpecialCase method calls
611
+ throw new Error("ToUpperSpecial: not implemented")
612
+ }
613
+
614
+ // ToLowerSpecial treats s as UTF-8-encoded bytes and returns a copy with all the Unicode letters mapped to their
615
+ // lower case, giving priority to the special casing rules.
616
+ export function ToLowerSpecial(c: unicode.SpecialCase, s: $.Bytes): $.Bytes {
617
+ // TODO: Fix SpecialCase method calls
618
+ throw new Error("ToLowerSpecial: not implemented")
619
+ }
620
+
621
+ // ToTitleSpecial treats s as UTF-8-encoded bytes and returns a copy with all the Unicode letters mapped to their
622
+ // title case, giving priority to the special casing rules.
623
+ export function ToTitleSpecial(c: unicode.SpecialCase, s: $.Bytes): $.Bytes {
624
+ // TODO: Fix SpecialCase method calls
625
+ throw new Error("ToTitleSpecial: not implemented")
626
+ }
627
+
628
+ // ToValidUTF8 treats s as UTF-8-encoded bytes and returns a copy with each run of bytes
629
+ // representing invalid UTF-8 replaced with the bytes in replacement, which may be empty.
630
+ export function ToValidUTF8(s: $.Bytes, replacement: $.Bytes): $.Bytes {
631
+ // TODO: Implement ToValidUTF8 with proper UTF-8 validation
632
+ throw new Error("ToValidUTF8: not implemented")
633
+ }
634
+
635
+ // isSeparator reports whether the rune could mark a word boundary.
636
+ // TODO: update when package unicode captures more of the properties.
637
+ export function isSeparator(r: number): boolean {
638
+ // ASCII alphanumerics and underscore are not separators
639
+ if (r <= 0x7F) {
640
+ if ((48 <= r && r <= 57) || // 0-9
641
+ (97 <= r && r <= 122) || // a-z
642
+ (65 <= r && r <= 90) || // A-Z
643
+ r === 95) { // _
644
+ return false
645
+ }
646
+ return true
647
+ }
648
+ // Letters and digits are not separators
649
+ if (unicode.IsLetter(r) || unicode.IsDigit(r)) {
650
+ return false
651
+ }
652
+ // Otherwise, all we can do for now is treat spaces as separators.
653
+ return unicode.IsSpace(r)
654
+ }
655
+
656
+ // Title treats s as UTF-8-encoded bytes and returns a copy with all Unicode letters that begin
657
+ // words mapped to their title case.
658
+ //
659
+ // Deprecated: The rule Title uses for word boundaries does not handle Unicode
660
+ // punctuation properly. Use golang.org/x/text/cases instead.
661
+ export function Title(s: $.Bytes): $.Bytes {
662
+ // TODO: Implement Title function properly
663
+ throw new Error("Title: not implemented")
664
+ }
665
+
666
+ // TrimLeftFunc treats s as UTF-8-encoded bytes and returns a subslice of s by slicing off
667
+ // all leading UTF-8-encoded code points c that satisfy f(c).
668
+ export function TrimLeftFunc(s: $.Bytes, f: ((r: number) => boolean) | null): $.Bytes {
669
+ const i = indexFunc(s, f, false)
670
+ if (i === -1) {
671
+ return null
672
+ }
673
+ return $.goSlice(s, i, undefined)
674
+ }
675
+
676
+ // TrimRightFunc returns a subslice of s by slicing off all trailing
677
+ // UTF-8-encoded code points c that satisfy f(c).
678
+ export function TrimRightFunc(s: $.Bytes, f: ((r: number) => boolean) | null): $.Bytes {
679
+ const i = lastIndexFunc(s, f, false)
680
+ if (i >= 0 && $.len(s) > i) {
681
+ const [, wid] = utf8.DecodeRune($.goSlice(s, i, undefined))
682
+ return $.goSlice(s, undefined, i + wid)
683
+ }
684
+ return null
685
+ }
686
+
687
+ // TrimFunc returns a subslice of s by slicing off all leading and trailing
688
+ // UTF-8-encoded code points c that satisfy f(c).
689
+ export function TrimFunc(s: $.Bytes, f: ((r: number) => boolean) | null): $.Bytes {
690
+ return TrimRightFunc(TrimLeftFunc(s, f), f)
691
+ }
692
+
693
+ // TrimPrefix returns s without the provided leading prefix string.
694
+ // If s doesn't start with prefix, s is returned unchanged.
695
+ export function TrimPrefix(s: $.Bytes, prefix: $.Bytes): $.Bytes {
696
+ if (HasPrefix(s, prefix)) {
697
+ return $.goSlice(s, $.len(prefix), undefined)
698
+ }
699
+ return s
700
+ }
701
+
702
+ // TrimSuffix returns s without the provided trailing suffix string.
703
+ // If s doesn't end with suffix, s is returned unchanged.
704
+ export function TrimSuffix(s: $.Bytes, suffix: $.Bytes): $.Bytes {
705
+ if (HasSuffix(s, suffix)) {
706
+ return $.goSlice(s, undefined, $.len(s) - $.len(suffix))
707
+ }
708
+ return s
709
+ }
710
+
711
+ // IndexFunc interprets s as a sequence of UTF-8-encoded code points.
712
+ // It returns the byte index in s of the first Unicode
713
+ // code point satisfying f(c), or -1 if none do.
714
+ export function IndexFunc(s: $.Bytes, f: ((r: number) => boolean) | null): number {
715
+ return indexFunc(s, f, true)
716
+ }
717
+
718
+ // LastIndexFunc interprets s as a sequence of UTF-8-encoded code points.
719
+ // It returns the byte index in s of the last Unicode
720
+ // code point satisfying f(c), or -1 if none do.
721
+ export function LastIndexFunc(s: $.Bytes, f: ((r: number) => boolean) | null): number {
722
+ return lastIndexFunc(s, f, true)
723
+ }
724
+
725
+ // indexFunc is the same as IndexFunc except that if
726
+ // truth==false, the sense of the predicate function is
727
+ // inverted.
728
+ export function indexFunc(s: $.Bytes, f: ((r: number) => boolean) | null, truth: boolean): number {
729
+ if (s === null || f === null) {
730
+ return -1
731
+ }
732
+
733
+ for (let i = 0; i < $.len(s); ) {
734
+ const [r, size] = utf8.DecodeRune($.goSlice(s, i, undefined))
735
+ if (size <= 0) {
736
+ // Invalid UTF-8
737
+ if (f(utf8.RuneError) === truth) {
738
+ return i
739
+ }
740
+ i++
741
+ } else {
742
+ if (f(r) === truth) {
743
+ return i
744
+ }
745
+ i += size
746
+ }
747
+ }
748
+
749
+ return -1
750
+ }
751
+
752
+ // lastIndexFunc is the same as LastIndexFunc except that if
753
+ // truth==false, the sense of the predicate function is
754
+ // inverted.
755
+ export function lastIndexFunc(s: $.Bytes, f: ((r: number) => boolean) | null, truth: boolean): number {
756
+ if (s === null || f === null) {
757
+ return -1
758
+ }
759
+
760
+ let lastIndex = -1
761
+
762
+ for (let i = 0; i < $.len(s); ) {
763
+ const [r, size] = utf8.DecodeRune($.goSlice(s, i, undefined))
764
+ if (size <= 0) {
765
+ // Invalid UTF-8
766
+ if (f(utf8.RuneError) === truth) {
767
+ lastIndex = i
768
+ }
769
+ i++
770
+ } else {
771
+ if (f(r) === truth) {
772
+ lastIndex = i
773
+ }
774
+ i += size
775
+ }
776
+ }
777
+
778
+ return lastIndex
779
+ }
780
+
781
+ class asciiSet {
782
+ constructor(public _value: number[]) {}
783
+
784
+ valueOf(): number[] {
785
+ return this._value
786
+ }
787
+
788
+ toString(): string {
789
+ return String(this._value)
790
+ }
791
+
792
+ static from(value: number[]): asciiSet {
793
+ return new asciiSet(value)
794
+ }
795
+
796
+ // contains reports whether c is inside the set.
797
+ public contains(c: number): boolean {
798
+ const _as = this._value
799
+ return ((_as![c >> 5] & (1 << (c & 31)))) !== 0
800
+ }
801
+ }
802
+
803
+ // makeASCIISet creates a set of ASCII characters and reports whether all
804
+ // characters in chars are ASCII.
805
+ export function makeASCIISet(chars: string): [asciiSet, boolean] {
806
+ const _as = new asciiSet([0, 0, 0, 0, 0, 0, 0, 0])
807
+
808
+ for (let i = 0; i < chars.length; i++) {
809
+ const c = chars.charCodeAt(i)
810
+ if (c >= utf8.RuneSelf) {
811
+ return [_as, false]
812
+ }
813
+ _as._value[c >> 5] |= (1 << (c & 31))
814
+ }
815
+
816
+ return [_as, true]
817
+ }
818
+
819
+ // containsRune is a simplified version of strings.ContainsRune
820
+ // to avoid importing the strings package.
821
+ // We avoid bytes.ContainsRune to avoid allocating a temporary copy of s.
822
+ export function containsRune(s: string, r: number): boolean {
823
+ for (let i = 0; i < s.length; ) {
824
+ const c = s.codePointAt(i)
825
+ if (c === r) return true
826
+ i += c! > 0xFFFF ? 2 : 1
827
+ }
828
+ return false
829
+ }
830
+
831
+ // Trim returns a subslice of s by slicing off all leading and
832
+ // trailing UTF-8-encoded code points contained in cutset.
833
+ export function Trim(s: $.Bytes, cutset: string): $.Bytes {
834
+ if (s === null || cutset.length === 0) {
835
+ return s
836
+ }
837
+
838
+ if (cutset.length === 1 && cutset.charCodeAt(0) < utf8.RuneSelf) {
839
+ // Single ASCII character optimization
840
+ return trimRightByte(trimLeftByte(s, cutset.charCodeAt(0)), cutset.charCodeAt(0))
841
+ }
842
+
843
+ const [as, allASCII] = makeASCIISet(cutset)
844
+ if (allASCII) {
845
+ return trimRightASCII(trimLeftASCII(s, as), as)
846
+ }
847
+
848
+ return trimRightUnicode(trimLeftUnicode(s, cutset), cutset)
849
+ }
850
+
851
+ // TrimLeft returns a subslice of s by slicing off all leading
852
+ // UTF-8-encoded code points contained in cutset.
853
+ export function TrimLeft(s: $.Bytes, cutset: string): $.Bytes {
854
+ if (s === null || cutset.length === 0) {
855
+ return s
856
+ }
857
+
858
+ if (cutset.length === 1 && cutset.charCodeAt(0) < utf8.RuneSelf) {
859
+ // Single ASCII character optimization
860
+ return trimLeftByte(s, cutset.charCodeAt(0))
861
+ }
862
+
863
+ const [as, allASCII] = makeASCIISet(cutset)
864
+ if (allASCII) {
865
+ return trimLeftASCII(s, as)
866
+ }
867
+
868
+ return trimLeftUnicode(s, cutset)
869
+ }
870
+
871
+ export function trimLeftByte(s: $.Bytes, c: number): $.Bytes {
872
+ if (s === null) return null
873
+
874
+ for (let i = 0; i < $.len(s); i++) {
875
+ if (s![i] !== c) {
876
+ return $.goSlice(s, i, undefined)
877
+ }
878
+ }
879
+
880
+ return null
881
+ }
882
+
883
+ export function trimLeftASCII(s: $.Bytes, _as: asciiSet): $.Bytes {
884
+ if (s === null) return null
885
+
886
+ for (let i = 0; i < $.len(s); i++) {
887
+ const b = s![i]
888
+ if (b >= utf8.RuneSelf || !_as.contains(b)) {
889
+ return $.goSlice(s, i, undefined)
890
+ }
891
+ }
892
+
893
+ return null
894
+ }
895
+
896
+ export function trimLeftUnicode(s: $.Bytes, cutset: string): $.Bytes {
897
+ if (s === null) return null
898
+
899
+ for (let i = 0; i < $.len(s); ) {
900
+ const [r, size] = utf8.DecodeRune($.goSlice(s, i, undefined))
901
+ if (size <= 0) {
902
+ // Invalid UTF-8, keep it
903
+ return $.goSlice(s, i, undefined)
904
+ }
905
+
906
+ if (!containsRune(cutset, r)) {
907
+ return $.goSlice(s, i, undefined)
908
+ }
909
+
910
+ i += size
911
+ }
912
+
913
+ return null
914
+ }
915
+
916
+ // TrimRight returns a subslice of s by slicing off all trailing
917
+ // UTF-8-encoded code points that are contained in cutset.
918
+ export function TrimRight(s: $.Bytes, cutset: string): $.Bytes {
919
+ if (s === null || cutset.length === 0) {
920
+ return s
921
+ }
922
+
923
+ if (cutset.length === 1 && cutset.charCodeAt(0) < utf8.RuneSelf) {
924
+ // Single ASCII character optimization
925
+ return trimRightByte(s, cutset.charCodeAt(0))
926
+ }
927
+
928
+ const [as, allASCII] = makeASCIISet(cutset)
929
+ if (allASCII) {
930
+ return trimRightASCII(s, as)
931
+ }
932
+
933
+ return trimRightUnicode(s, cutset)
934
+ }
935
+
936
+ export function trimRightByte(s: $.Bytes, c: number): $.Bytes {
937
+ if (s === null) return null
938
+
939
+ for (let i = $.len(s) - 1; i >= 0; i--) {
940
+ if (s![i] !== c) {
941
+ return $.goSlice(s, undefined, i + 1)
942
+ }
943
+ }
944
+
945
+ return null
946
+ }
947
+
948
+ export function trimRightASCII(s: $.Bytes, _as: asciiSet): $.Bytes {
949
+ if (s === null) return null
950
+
951
+ for (let i = $.len(s) - 1; i >= 0; i--) {
952
+ const b = s![i]
953
+ if (b >= utf8.RuneSelf || !_as.contains(b)) {
954
+ return $.goSlice(s, undefined, i + 1)
955
+ }
956
+ }
957
+
958
+ return null
959
+ }
960
+
961
+ export function trimRightUnicode(s: $.Bytes, cutset: string): $.Bytes {
962
+ if (s === null) return null
963
+
964
+ // Need to scan from left to find rune boundaries, but track the last non-cutset position
965
+ let lastKeep = -1
966
+
967
+ for (let i = 0; i < $.len(s); ) {
968
+ const [r, size] = utf8.DecodeRune($.goSlice(s, i, undefined))
969
+ if (size <= 0) {
970
+ // Invalid UTF-8, keep everything up to here
971
+ return $.goSlice(s, undefined, i + 1)
972
+ }
973
+
974
+ if (!containsRune(cutset, r)) {
975
+ lastKeep = i + size
976
+ }
977
+
978
+ i += size
979
+ }
980
+
981
+ if (lastKeep < 0) {
982
+ return null
983
+ }
984
+
985
+ return $.goSlice(s, undefined, lastKeep)
986
+ }
987
+
988
+ // TrimSpace returns a subslice of s by slicing off all leading and
989
+ // trailing white space, as defined by Unicode.
990
+ export function TrimSpace(s: $.Bytes): $.Bytes {
991
+ return TrimFunc(s, unicode.IsSpace)
992
+ }
993
+
994
+ // Runes interprets s as a sequence of UTF-8-encoded code points.
995
+ // It returns a slice of runes (Unicode code points) equivalent to s.
996
+ export function Runes(s: $.Bytes): $.Slice<number> {
997
+ if (s === null || $.len(s) === 0) {
998
+ return null
999
+ }
1000
+
1001
+ const result: number[] = []
1002
+
1003
+ for (let i = 0; i < $.len(s); ) {
1004
+ const [r, size] = utf8.DecodeRune($.goSlice(s, i, undefined))
1005
+ if (size <= 0) {
1006
+ // Invalid UTF-8, add replacement character
1007
+ result.push(utf8.RuneError)
1008
+ i++
1009
+ } else {
1010
+ result.push(r)
1011
+ i += size
1012
+ }
1013
+ }
1014
+
1015
+ return $.arrayToSlice(result)
1016
+ }
1017
+
1018
+ // Replace returns a copy of the slice s with the first n
1019
+ // non-overlapping instances of old replaced by new.
1020
+ // If old is empty, it matches at the beginning of the slice
1021
+ // and after each UTF-8 sequence, yielding up to k+1 replacements
1022
+ // for a k-rune slice.
1023
+ // If n < 0, there is no limit on the number of replacements.
1024
+ export function Replace(s: $.Bytes, old: $.Bytes, _new: $.Bytes, n: number): $.Bytes {
1025
+ if (s === null) {
1026
+ return new Uint8Array(0)
1027
+ }
1028
+
1029
+ if (n === 0) {
1030
+ // Make a copy without any replacements
1031
+ return new Uint8Array($.bytesToArray(s))
1032
+ }
1033
+
1034
+ // Handle empty old pattern - replace at beginning and after each UTF-8 sequence
1035
+ if (old === null || $.len(old) === 0) {
1036
+ const result: number[] = []
1037
+ const newBytes = _new === null ? [] : $.bytesToArray(_new)
1038
+
1039
+ // Add replacement at beginning
1040
+ if (n !== 0) {
1041
+ result.push(...newBytes)
1042
+ if (n > 0) n--
1043
+ }
1044
+
1045
+ // Add replacement after each UTF-8 sequence
1046
+ for (let i = 0; i < $.len(s) && n !== 0; ) {
1047
+ const [, size] = utf8.DecodeRune($.goSlice(s, i, undefined))
1048
+ if (size <= 0) {
1049
+ result.push(s![i])
1050
+ i++
1051
+ } else {
1052
+ // Add the rune bytes
1053
+ for (let j = 0; j < size; j++) {
1054
+ result.push(s![i + j])
1055
+ }
1056
+ i += size
1057
+ }
1058
+
1059
+ // Add replacement after this rune
1060
+ if (n !== 0) {
1061
+ result.push(...newBytes)
1062
+ if (n > 0) n--
1063
+ }
1064
+ }
1065
+
1066
+ return new Uint8Array(result)
1067
+ }
1068
+
1069
+ // Normal case - replace occurrences of old with new
1070
+ const result: number[] = []
1071
+ const sBytes = $.bytesToArray(s)
1072
+ const oldBytes = $.bytesToArray(old)
1073
+ const newBytes = _new === null ? [] : $.bytesToArray(_new)
1074
+
1075
+ let i = 0
1076
+ let replacements = 0
1077
+
1078
+ while (i <= sBytes.length - oldBytes.length && (n < 0 || replacements < n)) {
1079
+ // Check if old pattern matches at current position
1080
+ let matches = true
1081
+ for (let j = 0; j < oldBytes.length; j++) {
1082
+ if (sBytes[i + j] !== oldBytes[j]) {
1083
+ matches = false
1084
+ break
1085
+ }
1086
+ }
1087
+
1088
+ if (matches) {
1089
+ // Replace with new bytes
1090
+ result.push(...newBytes)
1091
+ i += oldBytes.length
1092
+ replacements++
1093
+ } else {
1094
+ // Copy one byte and advance
1095
+ result.push(sBytes[i])
1096
+ i++
1097
+ }
1098
+ }
1099
+
1100
+ // Copy remaining bytes
1101
+ while (i < sBytes.length) {
1102
+ result.push(sBytes[i])
1103
+ i++
1104
+ }
1105
+
1106
+ return new Uint8Array(result)
1107
+ }
1108
+
1109
+ // ReplaceAll returns a copy of the slice s with all
1110
+ // non-overlapping instances of old replaced by new.
1111
+ // If old is empty, it matches at the beginning of the slice
1112
+ // and after each UTF-8 sequence, yielding up to k+1 replacements
1113
+ // for a k-rune slice.
1114
+ export function ReplaceAll(s: $.Bytes, old: $.Bytes, _new: $.Bytes): $.Bytes {
1115
+ return Replace(s, old, _new, -1)
1116
+ }
1117
+
1118
+ // EqualFold reports whether s and t, interpreted as UTF-8 strings,
1119
+ // are equal under simple Unicode case-folding, which is a more general
1120
+ // form of case-insensitivity.
1121
+ export function EqualFold(s: $.Bytes, t: $.Bytes): boolean {
1122
+ // TODO: Implement EqualFold function properly (complex Unicode folding logic)
1123
+ throw new Error("EqualFold: not implemented")
1124
+ }
1125
+
1126
+ // Index returns the index of the first instance of sep in s, or -1 if sep is not present in s.
1127
+ export function Index(s: $.Bytes, sep: $.Bytes): number {
1128
+ return $.bytesIndexOf(s, sep)
1129
+ }
1130
+
1131
+ // Cut slices s around the first instance of sep,
1132
+ // returning the text before and after sep.
1133
+ // The found result reports whether sep appears in s.
1134
+ // If sep does not appear in s, cut returns s, nil, false.
1135
+ //
1136
+ // Cut returns slices of the original slice s, not copies.
1137
+ export function Cut(s: $.Bytes, sep: $.Bytes): [$.Bytes, $.Bytes, boolean] {
1138
+ const i = Index(s, sep)
1139
+ if (i >= 0) {
1140
+ return [$.goSlice(s, undefined, i), $.goSlice(s, i + $.len(sep), undefined), true]
1141
+ }
1142
+ return [s, null, false]
1143
+ }
1144
+
1145
+ // Clone returns a copy of b[:len(b)].
1146
+ // The result may have additional unused capacity.
1147
+ // Clone(nil) returns nil.
1148
+ export function Clone(b: $.Bytes): $.Bytes {
1149
+ if (b === null) {
1150
+ return null
1151
+ }
1152
+ return new Uint8Array($.bytesToArray(b))
1153
+ }
1154
+
1155
+ // CutPrefix returns s without the provided leading prefix byte slice
1156
+ // and reports whether it found the prefix.
1157
+ // If s doesn't start with prefix, CutPrefix returns s, false.
1158
+ // If prefix is the empty byte slice, CutPrefix returns s, true.
1159
+ //
1160
+ // CutPrefix returns slices of the original slice s, not copies.
1161
+ export function CutPrefix(s: $.Bytes, prefix: $.Bytes): [$.Bytes, boolean] {
1162
+ if (!HasPrefix(s, prefix)) {
1163
+ return [s, false]
1164
+ }
1165
+ return [$.goSlice(s, $.len(prefix), undefined), true]
1166
+ }
1167
+
1168
+ // CutSuffix returns s without the provided ending suffix byte slice
1169
+ // and reports whether it found the suffix.
1170
+ // If s doesn't end with suffix, CutSuffix returns s, false.
1171
+ // If suffix is the empty byte slice, CutSuffix returns s, true.
1172
+ //
1173
+ // CutSuffix returns slices of the original slice s, not copies.
1174
+ export function CutSuffix(s: $.Bytes, suffix: $.Bytes): [$.Bytes, boolean] {
1175
+ if (!HasSuffix(s, suffix)) {
1176
+ return [s, false]
1177
+ }
1178
+ return [$.goSlice(s, undefined, $.len(s) - $.len(suffix)), true]
1179
+ }
1180
+