nomen-lang 0.4.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/core/System/Arena.nm +6 -6
- package/core/System/Awaitable.nm +21 -0
- package/core/System/Buffer.nm +31 -15
- package/core/System/Channel.nm +82 -29
- package/core/System/ClassBuffer.nm +23 -9
- package/core/System/Controls/Button.nm +2 -2
- package/core/System/Controls/CheckBox.nm +2 -2
- package/core/System/Controls/Container.nm +3 -3
- package/core/System/Controls/TextBox.nm +2 -2
- package/core/System/Fiber.nm +201 -0
- package/core/System/Graph.nm +1 -1
- package/core/System/LinkedList.nm +1 -1
- package/core/System/List.nm +3 -3
- package/core/System/Map.nm +2 -2
- package/core/System/Mutex.nm +50 -54
- package/core/System/Nursery.nm +10 -8
- package/core/System/Option.nm +2 -2
- package/core/System/Random.nm +67 -0
- package/core/System/Result.nm +2 -2
- package/core/System/Set.nm +1 -1
- package/core/System/Spawnable.nm +18 -0
- package/core/System/Stream/File.nm +3 -3
- package/core/System/Stream/Http.nm +85 -436
- package/core/System/Stream/Tcp.nm +441 -0
- package/core/System/String.nm +7 -7
- package/core/System/StringBuilder.nm +1 -1
- package/core/System/Task.nm +145 -12
- package/core/System/Test.nm +20 -11
- package/core/System/Text/CharIndex.nm +8 -8
- package/core/System/Text/Chars.nm +1 -1
- package/core/System/Text/JsonTree.nm +1 -1
- package/core/System/Text/Regex.nm +122 -32
- package/core/System/Text/Utf8.nm +6 -6
- package/core/System/Thread.nm +199 -0
- package/core/System/Tree.nm +1 -1
- package/dist/index.mjs +19473 -13661
- package/package.json +1 -1
|
@@ -0,0 +1,441 @@
|
|
|
1
|
+
// Tcp — non-blocking sockets for Nomen tasks.
|
|
2
|
+
//
|
|
3
|
+
// Sockets are put in non-blocking mode and every wait goes through the
|
|
4
|
+
// runtime's netpoller hook (`__nomen_io_wait`): inside a Fiber the task parks
|
|
5
|
+
// (freeing its worker) until the socket is readable/writable; on a plain
|
|
6
|
+
// thread the hook blocks in poll(). So the same code scales from a handful of
|
|
7
|
+
// connections to thousands, and no call blocks a shared worker while it
|
|
8
|
+
// waits. See ASYNC.md Phase 3.
|
|
9
|
+
//
|
|
10
|
+
// Raw helpers return file descriptors / error codes (int-shaped), so the
|
|
11
|
+
// class wrappers construct the Tcp instances in Nomen. `error` mirrors
|
|
12
|
+
// Http's convention: 0 = ok, 1 = DNS, 2 = socket, 3 = connect, 4 = listen,
|
|
13
|
+
// 5 = closed.
|
|
14
|
+
//
|
|
15
|
+
// var Tcp server = Tcp.listen(8080, 128)
|
|
16
|
+
// async {
|
|
17
|
+
// var Tcp conn = server.accept()
|
|
18
|
+
// var bool ok = conn.send("hello")
|
|
19
|
+
// conn.close()
|
|
20
|
+
// }
|
|
21
|
+
//
|
|
22
|
+
// The method bodies are C (compiled directly on the C backend, and via the
|
|
23
|
+
// linked companion on aarch64) — OS socket/DNS interop, where hand-written
|
|
24
|
+
// per-target assembly is not practical.
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* A non-blocking TCP socket whose waits park the calling fiber
|
|
28
|
+
**/
|
|
29
|
+
pub class Tcp: Sendable {
|
|
30
|
+
// The underlying file descriptor, -1 when closed/failed.
|
|
31
|
+
pub var int fd = -1
|
|
32
|
+
// 0 = ok; 1 = DNS, 2 = socket, 3 = connect, 4 = listen, 5 = closed.
|
|
33
|
+
pub var error = 0
|
|
34
|
+
|
|
35
|
+
pub func #init = (self, int handle) {
|
|
36
|
+
self.fd = handle
|
|
37
|
+
self.error = 0
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
pub func #destroy = () {
|
|
41
|
+
```
|
|
42
|
+
#arch: c
|
|
43
|
+
if (self->fd >= 0) {
|
|
44
|
+
close(self->fd);
|
|
45
|
+
self->fd = -1;
|
|
46
|
+
}
|
|
47
|
+
```
|
|
48
|
+
```
|
|
49
|
+
#arch: aarch64_use_c
|
|
50
|
+
if (self->fd >= 0) {
|
|
51
|
+
close(self->fd);
|
|
52
|
+
self->fd = -1;
|
|
53
|
+
}
|
|
54
|
+
```
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
pub func close = (ref self) {
|
|
58
|
+
Tcp.close_fd(self.fd)
|
|
59
|
+
self.fd = -1
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
pub func is_open = (self, out bool) => self.fd >= 0
|
|
63
|
+
|
|
64
|
+
// ---- listening ----
|
|
65
|
+
|
|
66
|
+
// Create a listening socket bound to `port` on all interfaces.
|
|
67
|
+
pub func listen = (int port, int backlog, move out Tcp) {
|
|
68
|
+
var int handle = Tcp.listen_fd(port, backlog)
|
|
69
|
+
var t = Tcp(handle)
|
|
70
|
+
if handle < 0 {
|
|
71
|
+
t.error = 4
|
|
72
|
+
}
|
|
73
|
+
return t
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Accept the next connection, parking the fiber while the backlog is
|
|
77
|
+
// empty. The returned socket is -1 if the listener was cancelled or
|
|
78
|
+
// failed.
|
|
79
|
+
pub func accept = (ref self, move out Tcp) {
|
|
80
|
+
var int handle = Tcp.accept_fd(self.fd)
|
|
81
|
+
var t = Tcp(handle)
|
|
82
|
+
if handle < 0 {
|
|
83
|
+
t.error = 5
|
|
84
|
+
}
|
|
85
|
+
return t
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// ---- connecting ----
|
|
89
|
+
|
|
90
|
+
// Connect to `host`:`port`. Check `fd >= 0` (or `error == 0`) for success.
|
|
91
|
+
pub func connect = (string host, int port, move out Tcp) {
|
|
92
|
+
var int handle = Tcp.socket_fd()
|
|
93
|
+
if handle < 0 {
|
|
94
|
+
var bad = Tcp(-1)
|
|
95
|
+
bad.error = 2
|
|
96
|
+
return bad
|
|
97
|
+
}
|
|
98
|
+
var int err = Tcp.connect_to(handle, host, port)
|
|
99
|
+
if err != 0 {
|
|
100
|
+
Tcp.close_fd(handle)
|
|
101
|
+
var bad = Tcp(-1)
|
|
102
|
+
bad.error = err
|
|
103
|
+
return bad
|
|
104
|
+
}
|
|
105
|
+
return Tcp(handle)
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// ---- transferring ----
|
|
109
|
+
|
|
110
|
+
// Send every byte of `data`. Parks the fiber while the send buffer is
|
|
111
|
+
// full. Returns false on error or cancellation.
|
|
112
|
+
pub func send = (ref self, string data, out bool) {
|
|
113
|
+
return Tcp.send_all(self.fd, data)
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// Receive up to `max` bytes. Parks the fiber until data arrives; returns
|
|
117
|
+
// the empty string at end-of-stream, on error, or when cancelled.
|
|
118
|
+
pub func recv = (ref self, int max, move out string) {
|
|
119
|
+
return Tcp.recv_some(self.fd, max)
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// Receive until the peer closes (how Connection: close HTTP works).
|
|
123
|
+
pub func recv_all = (ref self, move out string) {
|
|
124
|
+
return Tcp.recv_until_close(self.fd)
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// ---- raw helpers (int-shaped, so the wrappers above build the Tcp) ----
|
|
128
|
+
|
|
129
|
+
func socket_fd = (out int) {
|
|
130
|
+
```
|
|
131
|
+
#arch: c
|
|
132
|
+
#scope: file
|
|
133
|
+
#include <sys/socket.h>
|
|
134
|
+
#include <netdb.h>
|
|
135
|
+
#include <netinet/in.h>
|
|
136
|
+
#include <arpa/inet.h>
|
|
137
|
+
#include <fcntl.h>
|
|
138
|
+
#include <unistd.h>
|
|
139
|
+
#include <string.h>
|
|
140
|
+
#include <stdlib.h>
|
|
141
|
+
#include <errno.h>
|
|
142
|
+
#include <stdbool.h>
|
|
143
|
+
```
|
|
144
|
+
```
|
|
145
|
+
#arch: c
|
|
146
|
+
int handle = socket(AF_INET, SOCK_STREAM, 0);
|
|
147
|
+
if (handle < 0) return -1;
|
|
148
|
+
fcntl(handle, F_SETFL, fcntl(handle, F_GETFL, 0) | O_NONBLOCK);
|
|
149
|
+
return handle;
|
|
150
|
+
```
|
|
151
|
+
```
|
|
152
|
+
#arch: aarch64_use_c
|
|
153
|
+
#scope: file
|
|
154
|
+
#include <sys/socket.h>
|
|
155
|
+
#include <netdb.h>
|
|
156
|
+
#include <netinet/in.h>
|
|
157
|
+
#include <arpa/inet.h>
|
|
158
|
+
#include <fcntl.h>
|
|
159
|
+
#include <unistd.h>
|
|
160
|
+
#include <string.h>
|
|
161
|
+
#include <stdlib.h>
|
|
162
|
+
#include <errno.h>
|
|
163
|
+
#include <stdbool.h>
|
|
164
|
+
```
|
|
165
|
+
```
|
|
166
|
+
#arch: aarch64_use_c
|
|
167
|
+
int handle = socket(AF_INET, SOCK_STREAM, 0);
|
|
168
|
+
if (handle < 0) return -1;
|
|
169
|
+
fcntl(handle, F_SETFL, fcntl(handle, F_GETFL, 0) | O_NONBLOCK);
|
|
170
|
+
return handle;
|
|
171
|
+
```
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
func listen_fd = (int port, int backlog, out int) {
|
|
175
|
+
```
|
|
176
|
+
#arch: c
|
|
177
|
+
int handle = socket(AF_INET, SOCK_STREAM, 0);
|
|
178
|
+
if (handle < 0) return -1;
|
|
179
|
+
int one = 1;
|
|
180
|
+
setsockopt(handle, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
|
|
181
|
+
struct sockaddr_in addr;
|
|
182
|
+
memset(&addr, 0, sizeof(addr));
|
|
183
|
+
addr.sin_family = AF_INET;
|
|
184
|
+
addr.sin_addr.s_addr = htonl(INADDR_ANY);
|
|
185
|
+
addr.sin_port = htons((unsigned short)port);
|
|
186
|
+
if (bind(handle, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
|
|
187
|
+
close(handle);
|
|
188
|
+
return -1;
|
|
189
|
+
}
|
|
190
|
+
if (listen(handle, backlog) < 0) {
|
|
191
|
+
close(handle);
|
|
192
|
+
return -1;
|
|
193
|
+
}
|
|
194
|
+
fcntl(handle, F_SETFL, fcntl(handle, F_GETFL, 0) | O_NONBLOCK);
|
|
195
|
+
return handle;
|
|
196
|
+
```
|
|
197
|
+
```
|
|
198
|
+
#arch: aarch64_use_c
|
|
199
|
+
int handle = socket(AF_INET, SOCK_STREAM, 0);
|
|
200
|
+
if (handle < 0) return -1;
|
|
201
|
+
int one = 1;
|
|
202
|
+
setsockopt(handle, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
|
|
203
|
+
struct sockaddr_in addr;
|
|
204
|
+
memset(&addr, 0, sizeof(addr));
|
|
205
|
+
addr.sin_family = AF_INET;
|
|
206
|
+
addr.sin_addr.s_addr = htonl(INADDR_ANY);
|
|
207
|
+
addr.sin_port = htons((unsigned short)port);
|
|
208
|
+
if (bind(handle, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
|
|
209
|
+
close(handle);
|
|
210
|
+
return -1;
|
|
211
|
+
}
|
|
212
|
+
if (listen(handle, backlog) < 0) {
|
|
213
|
+
close(handle);
|
|
214
|
+
return -1;
|
|
215
|
+
}
|
|
216
|
+
fcntl(handle, F_SETFL, fcntl(handle, F_GETFL, 0) | O_NONBLOCK);
|
|
217
|
+
return handle;
|
|
218
|
+
```
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
func accept_fd = (int listener, out int) {
|
|
222
|
+
```
|
|
223
|
+
#arch: c
|
|
224
|
+
for (;;) {
|
|
225
|
+
int handle = accept(listener, NULL, NULL);
|
|
226
|
+
if (handle >= 0) {
|
|
227
|
+
fcntl(handle, F_SETFL, fcntl(handle, F_GETFL, 0) | O_NONBLOCK);
|
|
228
|
+
return handle;
|
|
229
|
+
}
|
|
230
|
+
if (errno != EAGAIN && errno != EWOULDBLOCK && errno != EINTR) return -1;
|
|
231
|
+
if (!__nomen_io_wait(listener, 0)) return -1;
|
|
232
|
+
}
|
|
233
|
+
```
|
|
234
|
+
```
|
|
235
|
+
#arch: aarch64_use_c
|
|
236
|
+
for (;;) {
|
|
237
|
+
int handle = accept(listener, NULL, NULL);
|
|
238
|
+
if (handle >= 0) {
|
|
239
|
+
fcntl(handle, F_SETFL, fcntl(handle, F_GETFL, 0) | O_NONBLOCK);
|
|
240
|
+
return handle;
|
|
241
|
+
}
|
|
242
|
+
if (errno != EAGAIN && errno != EWOULDBLOCK && errno != EINTR) return -1;
|
|
243
|
+
if (!__nomen_io_wait(listener, 0)) return -1;
|
|
244
|
+
}
|
|
245
|
+
```
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
// Returns 0 on success, or an error code (1 = DNS, 3 = connect).
|
|
249
|
+
func connect_to = (int handle, string host, int port, out int) {
|
|
250
|
+
```
|
|
251
|
+
#arch: c
|
|
252
|
+
char portstr[16];
|
|
253
|
+
snprintf(portstr, sizeof(portstr), "%d", port);
|
|
254
|
+
struct addrinfo hints, *res = NULL;
|
|
255
|
+
memset(&hints, 0, sizeof(hints));
|
|
256
|
+
hints.ai_family = AF_INET;
|
|
257
|
+
hints.ai_socktype = SOCK_STREAM;
|
|
258
|
+
if (getaddrinfo(host.ptr, portstr, &hints, &res) != 0) return 1;
|
|
259
|
+
int rc = connect(handle, res->ai_addr, res->ai_addrlen);
|
|
260
|
+
freeaddrinfo(res);
|
|
261
|
+
if (rc == 0) return 0;
|
|
262
|
+
if (errno != EINPROGRESS) return 3;
|
|
263
|
+
if (!__nomen_io_wait(handle, 1)) return 3;
|
|
264
|
+
int so_err = 0;
|
|
265
|
+
socklen_t so_len = sizeof(so_err);
|
|
266
|
+
if (getsockopt(handle, SOL_SOCKET, SO_ERROR, &so_err, &so_len) < 0) return 3;
|
|
267
|
+
return so_err == 0 ? 0 : 3;
|
|
268
|
+
```
|
|
269
|
+
```
|
|
270
|
+
#arch: aarch64_use_c
|
|
271
|
+
char portstr[16];
|
|
272
|
+
snprintf(portstr, sizeof(portstr), "%d", port);
|
|
273
|
+
struct addrinfo hints, *res = NULL;
|
|
274
|
+
memset(&hints, 0, sizeof(hints));
|
|
275
|
+
hints.ai_family = AF_INET;
|
|
276
|
+
hints.ai_socktype = SOCK_STREAM;
|
|
277
|
+
if (getaddrinfo(host.ptr, portstr, &hints, &res) != 0) return 1;
|
|
278
|
+
int rc = connect(handle, res->ai_addr, res->ai_addrlen);
|
|
279
|
+
freeaddrinfo(res);
|
|
280
|
+
if (rc == 0) return 0;
|
|
281
|
+
if (errno != EINPROGRESS) return 3;
|
|
282
|
+
if (!__nomen_io_wait(handle, 1)) return 3;
|
|
283
|
+
int so_err = 0;
|
|
284
|
+
socklen_t so_len = sizeof(so_err);
|
|
285
|
+
if (getsockopt(handle, SOL_SOCKET, SO_ERROR, &so_err, &so_len) < 0) return 3;
|
|
286
|
+
return so_err == 0 ? 0 : 3;
|
|
287
|
+
```
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
func send_all = (int handle, string data, out bool) {
|
|
291
|
+
```
|
|
292
|
+
#arch: c
|
|
293
|
+
long off = 0;
|
|
294
|
+
while (off < data.len) {
|
|
295
|
+
ssize_t n = send(handle, data.ptr + off, (size_t)(data.len - off), 0);
|
|
296
|
+
if (n > 0) {
|
|
297
|
+
off += (long)n;
|
|
298
|
+
continue;
|
|
299
|
+
}
|
|
300
|
+
if (errno == EAGAIN || errno == EWOULDBLOCK) {
|
|
301
|
+
if (!__nomen_io_wait(handle, 1)) return false;
|
|
302
|
+
continue;
|
|
303
|
+
}
|
|
304
|
+
if (errno == EINTR) continue;
|
|
305
|
+
return false;
|
|
306
|
+
}
|
|
307
|
+
return true;
|
|
308
|
+
```
|
|
309
|
+
```
|
|
310
|
+
#arch: aarch64_use_c
|
|
311
|
+
long off = 0;
|
|
312
|
+
while (off < data.len) {
|
|
313
|
+
ssize_t n = send(handle, data.ptr + off, (size_t)(data.len - off), 0);
|
|
314
|
+
if (n > 0) {
|
|
315
|
+
off += (long)n;
|
|
316
|
+
continue;
|
|
317
|
+
}
|
|
318
|
+
if (errno == EAGAIN || errno == EWOULDBLOCK) {
|
|
319
|
+
if (!__nomen_io_wait(handle, 1)) return false;
|
|
320
|
+
continue;
|
|
321
|
+
}
|
|
322
|
+
if (errno == EINTR) continue;
|
|
323
|
+
return false;
|
|
324
|
+
}
|
|
325
|
+
return true;
|
|
326
|
+
```
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
func recv_some = (int handle, int max, move out string) {
|
|
330
|
+
```
|
|
331
|
+
#arch: c
|
|
332
|
+
long cap = max > 0 ? max : 1;
|
|
333
|
+
char *buf = (char *)malloc((size_t)cap);
|
|
334
|
+
for (;;) {
|
|
335
|
+
ssize_t n = recv(handle, buf, (size_t)cap, 0);
|
|
336
|
+
if (n > 0) return (nomen_string){ buf, (long)n };
|
|
337
|
+
if (n == 0) {
|
|
338
|
+
free(buf);
|
|
339
|
+
return (nomen_string){ strdup(""), 0 };
|
|
340
|
+
}
|
|
341
|
+
if (errno == EAGAIN || errno == EWOULDBLOCK) {
|
|
342
|
+
if (!__nomen_io_wait(handle, 0)) {
|
|
343
|
+
free(buf);
|
|
344
|
+
return (nomen_string){ strdup(""), 0 };
|
|
345
|
+
}
|
|
346
|
+
continue;
|
|
347
|
+
}
|
|
348
|
+
if (errno == EINTR) continue;
|
|
349
|
+
free(buf);
|
|
350
|
+
return (nomen_string){ strdup(""), 0 };
|
|
351
|
+
}
|
|
352
|
+
```
|
|
353
|
+
```
|
|
354
|
+
#arch: aarch64_use_c
|
|
355
|
+
long cap = max > 0 ? max : 1;
|
|
356
|
+
char *buf = (char *)malloc((size_t)cap);
|
|
357
|
+
for (;;) {
|
|
358
|
+
ssize_t n = recv(handle, buf, (size_t)cap, 0);
|
|
359
|
+
if (n > 0) return (nomen_string){ buf, (long)n };
|
|
360
|
+
if (n == 0) {
|
|
361
|
+
free(buf);
|
|
362
|
+
return (nomen_string){ strdup(""), 0 };
|
|
363
|
+
}
|
|
364
|
+
if (errno == EAGAIN || errno == EWOULDBLOCK) {
|
|
365
|
+
if (!__nomen_io_wait(handle, 0)) {
|
|
366
|
+
free(buf);
|
|
367
|
+
return (nomen_string){ strdup(""), 0 };
|
|
368
|
+
}
|
|
369
|
+
continue;
|
|
370
|
+
}
|
|
371
|
+
if (errno == EINTR) continue;
|
|
372
|
+
free(buf);
|
|
373
|
+
return (nomen_string){ strdup(""), 0 };
|
|
374
|
+
}
|
|
375
|
+
```
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
func recv_until_close = (int handle, move out string) {
|
|
379
|
+
```
|
|
380
|
+
#arch: c
|
|
381
|
+
long cap = 4096, len = 0;
|
|
382
|
+
char *buf = (char *)malloc((size_t)cap);
|
|
383
|
+
for (;;) {
|
|
384
|
+
if (len + 1 >= cap) {
|
|
385
|
+
cap *= 2;
|
|
386
|
+
buf = (char *)realloc(buf, (size_t)cap);
|
|
387
|
+
}
|
|
388
|
+
ssize_t n = recv(handle, buf + len, (size_t)(cap - len - 1), 0);
|
|
389
|
+
if (n > 0) {
|
|
390
|
+
len += (long)n;
|
|
391
|
+
continue;
|
|
392
|
+
}
|
|
393
|
+
if (n == 0) break;
|
|
394
|
+
if (errno == EAGAIN || errno == EWOULDBLOCK) {
|
|
395
|
+
if (!__nomen_io_wait(handle, 0)) break;
|
|
396
|
+
continue;
|
|
397
|
+
}
|
|
398
|
+
if (errno == EINTR) continue;
|
|
399
|
+
break;
|
|
400
|
+
}
|
|
401
|
+
buf[len] = 0;
|
|
402
|
+
return (nomen_string){ buf, len };
|
|
403
|
+
```
|
|
404
|
+
```
|
|
405
|
+
#arch: aarch64_use_c
|
|
406
|
+
long cap = 4096, len = 0;
|
|
407
|
+
char *buf = (char *)malloc((size_t)cap);
|
|
408
|
+
for (;;) {
|
|
409
|
+
if (len + 1 >= cap) {
|
|
410
|
+
cap *= 2;
|
|
411
|
+
buf = (char *)realloc(buf, (size_t)cap);
|
|
412
|
+
}
|
|
413
|
+
ssize_t n = recv(handle, buf + len, (size_t)(cap - len - 1), 0);
|
|
414
|
+
if (n > 0) {
|
|
415
|
+
len += (long)n;
|
|
416
|
+
continue;
|
|
417
|
+
}
|
|
418
|
+
if (n == 0) break;
|
|
419
|
+
if (errno == EAGAIN || errno == EWOULDBLOCK) {
|
|
420
|
+
if (!__nomen_io_wait(handle, 0)) break;
|
|
421
|
+
continue;
|
|
422
|
+
}
|
|
423
|
+
if (errno == EINTR) continue;
|
|
424
|
+
break;
|
|
425
|
+
}
|
|
426
|
+
buf[len] = 0;
|
|
427
|
+
return (nomen_string){ buf, len };
|
|
428
|
+
```
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
func close_fd = (int handle) {
|
|
432
|
+
```
|
|
433
|
+
#arch: c
|
|
434
|
+
if (handle >= 0) close(handle);
|
|
435
|
+
```
|
|
436
|
+
```
|
|
437
|
+
#arch: aarch64_use_c
|
|
438
|
+
if (handle >= 0) close(handle);
|
|
439
|
+
```
|
|
440
|
+
}
|
|
441
|
+
}
|
package/core/System/String.nm
CHANGED
|
@@ -248,7 +248,7 @@ pub struct string: Stringable, Hashable, Equatable {
|
|
|
248
248
|
// are only ever read.
|
|
249
249
|
pub func replace_first = (self, view string needle, view string replacement, out string) {
|
|
250
250
|
var sb = StringBuilder()
|
|
251
|
-
var
|
|
251
|
+
var i = 0
|
|
252
252
|
var int n = self.length
|
|
253
253
|
var int nlen = needle.length
|
|
254
254
|
var bool replaced = nlen == 0
|
|
@@ -269,7 +269,7 @@ pub struct string: Stringable, Hashable, Equatable {
|
|
|
269
269
|
// left to right. Same edge behavior as replace_first.
|
|
270
270
|
pub func replace_all = (self, view string needle, view string replacement, out string) {
|
|
271
271
|
var sb = StringBuilder()
|
|
272
|
-
var
|
|
272
|
+
var i = 0
|
|
273
273
|
var int n = self.length
|
|
274
274
|
var int nlen = needle.length
|
|
275
275
|
while i < n {
|
|
@@ -391,7 +391,7 @@ pub struct string: Stringable, Hashable, Equatable {
|
|
|
391
391
|
// Owned copy of self with leading and trailing ASCII whitespace
|
|
392
392
|
// (tab, LF, VT, FF, CR, space) removed. All-whitespace yields "".
|
|
393
393
|
pub func trim = (self, out string) {
|
|
394
|
-
var
|
|
394
|
+
var start = 0
|
|
395
395
|
while start < self.length; start += 1 {
|
|
396
396
|
if !self.at(start).is_ascii_space() {
|
|
397
397
|
break
|
|
@@ -421,7 +421,7 @@ pub struct string: Stringable, Hashable, Equatable {
|
|
|
421
421
|
|
|
422
422
|
// Owned copy of self with leading ASCII whitespace removed.
|
|
423
423
|
pub func trim_start = (self, out string) {
|
|
424
|
-
var
|
|
424
|
+
var start = 0
|
|
425
425
|
while start < self.length; start += 1 {
|
|
426
426
|
if !self.at(start).is_ascii_space() {
|
|
427
427
|
break
|
|
@@ -435,7 +435,7 @@ pub struct string: Stringable, Hashable, Equatable {
|
|
|
435
435
|
// bytes — including UTF-8 sequences — pass through unchanged).
|
|
436
436
|
pub func to_lowercase = (self, out string) {
|
|
437
437
|
var sb = StringBuilder()
|
|
438
|
-
var
|
|
438
|
+
var i = 0
|
|
439
439
|
while i < self.length; i += 1 {
|
|
440
440
|
var int code = self.at(i) as int
|
|
441
441
|
if code > 64 && code < 91 {
|
|
@@ -450,7 +450,7 @@ pub struct string: Stringable, Hashable, Equatable {
|
|
|
450
450
|
// bytes — including UTF-8 sequences — pass through unchanged).
|
|
451
451
|
pub func to_uppercase = (self, out string) {
|
|
452
452
|
var sb = StringBuilder()
|
|
453
|
-
var
|
|
453
|
+
var i = 0
|
|
454
454
|
while i < self.length; i += 1 {
|
|
455
455
|
var int code = self.at(i) as int
|
|
456
456
|
if code > 96 && code < 123 {
|
|
@@ -465,7 +465,7 @@ pub struct string: Stringable, Hashable, Equatable {
|
|
|
465
465
|
// needle matches text at byte offset pos (caller guarantees pos + len fits;
|
|
466
466
|
// the trailing guard makes the bound explicit so `.at` verifies).
|
|
467
467
|
func match_at = (view string text, view string needle, int pos, out bool) {
|
|
468
|
-
var
|
|
468
|
+
var i = 0
|
|
469
469
|
var int nlen = needle.length
|
|
470
470
|
var int n = text.length
|
|
471
471
|
while i < nlen && pos + i < n {
|