nomen-lang 0.6.12 → 0.7.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/NOMEN_AGENTS.md +27 -13
- package/audit_runtime.c +2 -0
- package/core/System/Arena.nm +4 -4
- package/core/System/Array.nm +108 -78
- package/core/System/Atomic.nm +81 -0
- package/core/System/Awaitable.nm +12 -5
- package/core/System/BigInt.nm +1 -1
- package/core/System/Box.nm +32 -0
- package/core/System/Buffer.nm +47 -18
- package/core/System/Channel.nm +27 -11
- package/core/System/ClassBuffer.nm +24 -28
- package/core/System/Console.nm +4 -4
- package/core/System/Controls/Button.nm +8 -3
- package/core/System/Controls/CheckBox.nm +8 -3
- package/core/System/Controls/Container.nm +18 -11
- package/core/System/Controls/Layout.nm +1 -1
- package/core/System/Controls/Text.nm +9 -4
- package/core/System/Controls/TextBox.nm +8 -3
- package/core/System/Controls/Window.nm +10 -3
- package/core/System/Fiber.nm +6 -2
- package/core/System/Graph.nm +2 -2
- package/core/System/Init.nm +2 -2
- package/core/System/LinkedList.nm +2 -2
- package/core/System/List.nm +7 -7
- package/core/System/Map.nm +10 -7
- package/core/System/Math.nm +1 -1
- package/core/System/Mutex.nm +14 -2
- package/core/System/Random.nm +7 -1
- package/core/System/Result.nm +1 -1
- package/core/System/Sendable.nm +2 -2
- package/core/System/Set.nm +6 -6
- package/core/System/Spawnable.nm +9 -9
- package/core/System/Stream/Directory.nm +1 -2
- package/core/System/Stream/File.nm +8 -9
- package/core/System/Stream/Http.nm +2 -3
- package/core/System/Stream/Tcp.nm +13 -8
- package/core/System/String.nm +22 -12
- package/core/System/StringBuilder.nm +2 -2
- package/core/System/Task.nm +21 -29
- package/core/System/Test.nm +10 -4
- package/core/System/Text/CharIndex.nm +2 -3
- package/core/System/Text/Json.nm +8 -12
- package/core/System/Text/JsonTree.nm +4 -4
- package/core/System/Text/Regex.nm +7 -7
- package/core/System/Text/Utf8.nm +2 -3
- package/core/System/Thread.nm +9 -4
- package/core/System/Tree.nm +2 -2
- package/core/System/Viewable.nm +2 -2
- package/core/System/WeakHandle.nm +56 -0
- package/core/System/bool.nm +1 -1
- package/core/System/char.nm +1 -1
- package/core/System/float.nm +1 -1
- package/core/System/float32.nm +1 -1
- package/core/System/float64.nm +1 -1
- package/core/System/int.nm +1 -1
- package/core/System/int16.nm +1 -1
- package/core/System/int32.nm +1 -1
- package/core/System/int64.nm +1 -1
- package/core/System/int8.nm +1 -1
- package/core/System/ufloat.nm +1 -1
- package/core/System/ufloat32.nm +1 -1
- package/core/System/ufloat64.nm +1 -1
- package/core/System/uint.nm +1 -1
- package/core/System/uint16.nm +1 -1
- package/core/System/uint32.nm +1 -1
- package/core/System/uint64.nm +1 -1
- package/core/System/uint8.nm +1 -1
- package/core/docs/System/Result.md +2 -2
- package/dist/index.mjs +28088 -24186
- package/package.json +1 -1
- package/src/test.ts +26 -11
package/core/System/Graph.nm
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
/**
|
|
7
7
|
* A graph of values connected by edges
|
|
8
8
|
**/
|
|
9
|
-
pub struct Graph<T>: Enumerable {
|
|
9
|
+
pub mv struct Graph<T>: Enumerable {
|
|
10
10
|
var values = Buffer<T>()
|
|
11
11
|
var head_edge = Buffer<int>()
|
|
12
12
|
var edge_target = Buffer<int>()
|
|
@@ -14,7 +14,7 @@ pub struct Graph<T>: Enumerable {
|
|
|
14
14
|
var node_count = 0
|
|
15
15
|
var edge_count = 0
|
|
16
16
|
|
|
17
|
-
pub func add_node = (ref self,
|
|
17
|
+
pub func add_node = (ref self, mv T value) {
|
|
18
18
|
var int idx = self.node_count
|
|
19
19
|
self.values.grow(idx + 1)
|
|
20
20
|
self.values.store(idx, value)
|
package/core/System/Init.nm
CHANGED
|
@@ -2,14 +2,14 @@
|
|
|
2
2
|
* Program startup state — the argument count and argument list passed to `main`,
|
|
3
3
|
* plus whether stdout is a terminal (for renderer selection).
|
|
4
4
|
**/
|
|
5
|
-
pub struct Init {
|
|
5
|
+
pub mv struct Init {
|
|
6
6
|
var int argc
|
|
7
7
|
var string[16] args
|
|
8
8
|
var bool is_tty
|
|
9
9
|
}
|
|
10
10
|
|
|
11
11
|
// FFI: the C library's decimal-string parser (stdlib.h).
|
|
12
|
-
|
|
12
|
+
foreign func atoi = (string s, out int)
|
|
13
13
|
|
|
14
14
|
/**
|
|
15
15
|
* Parses a decimal string into an int
|
|
@@ -6,14 +6,14 @@
|
|
|
6
6
|
/**
|
|
7
7
|
* A doubly-linked list of values
|
|
8
8
|
**/
|
|
9
|
-
pub struct LinkedList<T>: Enumerable {
|
|
9
|
+
pub mv struct LinkedList<T>: Enumerable {
|
|
10
10
|
var values = Buffer<T>()
|
|
11
11
|
var nexts = Buffer<int>()
|
|
12
12
|
var prevs = Buffer<int>()
|
|
13
13
|
var int head = -1
|
|
14
14
|
var count = 0
|
|
15
15
|
|
|
16
|
-
pub func add = (ref self,
|
|
16
|
+
pub func add = (ref self, mv T value) {
|
|
17
17
|
var int idx = self.count
|
|
18
18
|
self.values.grow(idx + 1)
|
|
19
19
|
self.values.store(idx, value)
|
package/core/System/List.nm
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* A growable, ordered list of values (`push`/`pop`/`at`)
|
|
3
3
|
**/
|
|
4
|
-
pub struct List<T>: Viewable {
|
|
4
|
+
pub mv struct List<T>: Viewable {
|
|
5
5
|
var length = 0
|
|
6
6
|
var items = Buffer<T>()
|
|
7
7
|
|
|
8
|
-
pub func push = (ref self,
|
|
8
|
+
pub func push = (ref self, mv T value) {
|
|
9
9
|
if self.length >= self.items.cap {
|
|
10
10
|
var new_cap = 4
|
|
11
11
|
var int old_cap = self.items.cap
|
|
@@ -18,7 +18,7 @@ pub struct List<T>: Viewable {
|
|
|
18
18
|
self.length += 1
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
-
pub func pop = (ref self,
|
|
21
|
+
pub func pop = (ref self, mv out T) {
|
|
22
22
|
if self.length <= 0 {
|
|
23
23
|
return self.items.move(0)
|
|
24
24
|
}
|
|
@@ -51,13 +51,13 @@ pub struct List<T>: Viewable {
|
|
|
51
51
|
panic("index out of range")
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
-
// A non-
|
|
54
|
+
// A non-mv `view T` over [start, end). Delegates to the backing Buffer's
|
|
55
55
|
// #arch slice primitive — no #arch code here. Borrows from self.
|
|
56
56
|
pub func slice = (self, int start: start >= 0, int end: end >= start, out view T) {
|
|
57
57
|
return self.items.slice(start, end)
|
|
58
58
|
}
|
|
59
59
|
|
|
60
|
-
pub func set = (ref self, int i: i >= 0 && i < self.length,
|
|
60
|
+
pub func set = (ref self, int i: i >= 0 && i < self.length, mv T value) {
|
|
61
61
|
self.items.replace(i, value)
|
|
62
62
|
}
|
|
63
63
|
|
|
@@ -65,7 +65,7 @@ pub struct List<T>: Viewable {
|
|
|
65
65
|
// for indices that can't be proven at compile time (cross-module calls
|
|
66
66
|
// can never discharge `set`'s parameter constraint) and out-of-range is
|
|
67
67
|
// a bug, not a case.
|
|
68
|
-
pub func set_or_panic = (ref self, int i,
|
|
68
|
+
pub func set_or_panic = (ref self, int i, mv T value) {
|
|
69
69
|
if i >= 0 && i < self.length {
|
|
70
70
|
self.set(i, value)
|
|
71
71
|
return
|
|
@@ -74,7 +74,7 @@ pub struct List<T>: Viewable {
|
|
|
74
74
|
}
|
|
75
75
|
|
|
76
76
|
// A deep copy: a fresh List<T> with an independent copy of every element.
|
|
77
|
-
// For
|
|
77
|
+
// For mv element types (strings, mv value structs) each slot in the
|
|
78
78
|
// copy owns its own heap data (Buffer deep-copies on store), so the source
|
|
79
79
|
// and the copy share nothing. Not available for class/trait element types
|
|
80
80
|
// (the copy would share the stored instances — the checker rejects it).
|
package/core/System/Map.nm
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* it is correct for negative hashes too: two's-complement `&` already lands
|
|
9
9
|
* in `[0, cap)`, which is why no negative adjustment is needed.
|
|
10
10
|
**/
|
|
11
|
-
pub struct Map<TK: Hashable + Equatable, TV> {
|
|
11
|
+
pub mv struct Map<TK: Hashable + Equatable, TV> {
|
|
12
12
|
var length = 0
|
|
13
13
|
var keys = Buffer<TK>()
|
|
14
14
|
var values = Buffer<TV>()
|
|
@@ -17,6 +17,9 @@ pub struct Map<TK: Hashable + Equatable, TV> {
|
|
|
17
17
|
// Variadic-tuple constructor: Map<string, int>(["a", 1], ["b", 2]) or
|
|
18
18
|
// Map(["a", 1], ["b", 2]) (type args inferred from the first pair).
|
|
19
19
|
// Zero pairs yields an empty Map, so this also covers Map<K, V>().
|
|
20
|
+
// The pair reads are temp-rooted (`pairs.at(i)` is a statement temp):
|
|
21
|
+
// the element transfer is absorbed by set's mv store (store_T
|
|
22
|
+
// deep-copies string-field elements), so no explicit mv is spelled.
|
|
20
23
|
pub func #init = (self, ...[TK, TV] pairs) {
|
|
21
24
|
var i = 0
|
|
22
25
|
while i < pairs.length; i += 1 {
|
|
@@ -24,7 +27,7 @@ pub struct Map<TK: Hashable + Equatable, TV> {
|
|
|
24
27
|
}
|
|
25
28
|
}
|
|
26
29
|
|
|
27
|
-
pub func set = (ref self,
|
|
30
|
+
pub func set = (ref self, mv TK key, mv TV value) {
|
|
28
31
|
var int cap = self.keys.cap
|
|
29
32
|
if cap == 0 {
|
|
30
33
|
// alloc_T: for Buffer<TK> it is T_SIZE-aware (string keys are
|
|
@@ -169,9 +172,9 @@ pub struct Map<TK: Hashable + Equatable, TV> {
|
|
|
169
172
|
}
|
|
170
173
|
|
|
171
174
|
func rehash = (ref self, int new_cap) {
|
|
172
|
-
var Buffer<TK> old_keys =
|
|
173
|
-
var Buffer<TV> old_values =
|
|
174
|
-
var Buffer<int> old_used =
|
|
175
|
+
var Buffer<TK> old_keys = mv self.keys swap Buffer<TK>()
|
|
176
|
+
var Buffer<TV> old_values = mv self.values swap Buffer<TV>()
|
|
177
|
+
var Buffer<int> old_used = mv self.used swap Buffer<int>()
|
|
175
178
|
var int old_cap = old_keys.cap
|
|
176
179
|
|
|
177
180
|
self.keys.alloc(new_cap)
|
|
@@ -187,13 +190,13 @@ pub struct Map<TK: Hashable + Equatable, TV> {
|
|
|
187
190
|
// afterwards. load_T would leave the old slot referencing
|
|
188
191
|
// the same class pointer — a double-free when old_keys is
|
|
189
192
|
// destroyed. The results are bound to locals so an
|
|
190
|
-
//
|
|
193
|
+
// mv-element copy (e.g. a `Buffer<string>` slot, which
|
|
191
194
|
// store_T strdup's) is freed here once the new buffer has
|
|
192
195
|
// made its own copy — passing them inline would orphan the
|
|
193
196
|
// move_T results.
|
|
194
197
|
var TK k = old_keys.move(i)
|
|
195
198
|
var TV v = old_values.move(i)
|
|
196
|
-
self.set(
|
|
199
|
+
self.set(mv k, mv v)
|
|
197
200
|
}
|
|
198
201
|
}
|
|
199
202
|
}
|
package/core/System/Math.nm
CHANGED
package/core/System/Mutex.nm
CHANGED
|
@@ -10,16 +10,28 @@
|
|
|
10
10
|
// observes the cancel flag at its next checkpoint after acquiring — so a
|
|
11
11
|
// matching unlock is always sound.
|
|
12
12
|
|
|
13
|
+
// Mutex is an OWNING STRUCT (STRUCT_PLAN_3 Phase R, tranche 3 — the shape
|
|
14
|
+
// menu): the single field is an opaque handle, so the value is movable and
|
|
15
|
+
// its `#destroy` closes what the handle names. Moving a Mutex transfers the
|
|
16
|
+
// handle; there is no aliasing copy to misuse. Sharing one across tasks
|
|
17
|
+
// rides the checked region borrows (`async { }`) — the lock/unlock methods
|
|
18
|
+
// take the receiver bare (struct receivers travel by address), so a locked
|
|
19
|
+
// section mutates the kernel object the handle names, never the binding.
|
|
20
|
+
|
|
13
21
|
/**
|
|
14
22
|
* A pthread-backed mutual-exclusion lock for protecting shared mutable state
|
|
15
23
|
**/
|
|
16
|
-
pub
|
|
24
|
+
pub mv struct Mutex {
|
|
17
25
|
pub var uint64 handle = 0
|
|
18
26
|
|
|
19
27
|
pub func #init = (self) {
|
|
28
|
+
// The constructor's `self` is the INLINE instance (a local value in the
|
|
29
|
+
// C lowering — methods take the pointer form, the ctor does not), so the
|
|
30
|
+
// C body uses the `.` accessor; the aarch64 body writes through x19 =
|
|
31
|
+
// &instance as always.
|
|
20
32
|
```
|
|
21
33
|
#arch: c
|
|
22
|
-
self
|
|
34
|
+
self.handle = (unsigned long long)__nomen_mutex_create();
|
|
23
35
|
```
|
|
24
36
|
```
|
|
25
37
|
#arch: aarch64
|
package/core/System/Random.nm
CHANGED
|
@@ -15,10 +15,16 @@
|
|
|
15
15
|
//
|
|
16
16
|
import Time
|
|
17
17
|
|
|
18
|
+
// Random is an OWNING STRUCT (STRUCT_PLAN_3 Phase R, tranche 3 — the shape
|
|
19
|
+
// menu): bindings mv instead of alias. The state is a bare uint64, so the
|
|
20
|
+
// value is freely movable (and trivially copyable in principle — `mv`
|
|
21
|
+
// is the uniform spelling for the launch/IO primitives; a `ref Random`
|
|
22
|
+
// parameter is the read-only borrow that keeps one stream per binding).
|
|
23
|
+
|
|
18
24
|
/**
|
|
19
25
|
* A fast splitmix64 pseudo-random number generator
|
|
20
26
|
**/
|
|
21
|
-
pub
|
|
27
|
+
pub mv struct Random {
|
|
22
28
|
// The raw 64-bit generator state (seeded from the wall clock by the
|
|
23
29
|
// no-arg constructor, or an explicit seed for reproducible sequences).
|
|
24
30
|
pub var uint64 state = 0
|
package/core/System/Result.nm
CHANGED
package/core/System/Sendable.nm
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
// Marker trait for types whose values are safe to
|
|
1
|
+
// Marker trait for types whose values are safe to mv across task boundaries.
|
|
2
2
|
// See ASYNC.md for the design. Auto-derivable in a follow-up; for now, structs
|
|
3
3
|
// opt in explicitly with `: Sendable`.
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
|
-
* A marker trait for values that are safe to
|
|
6
|
+
* A marker trait for values that are safe to mv across task boundaries
|
|
7
7
|
**/
|
|
8
8
|
pub trait Sendable {
|
|
9
9
|
}
|
package/core/System/Set.nm
CHANGED
|
@@ -7,12 +7,12 @@
|
|
|
7
7
|
* slot indexing is a mask (`hash & (cap - 1)`) — correct for negative hashes
|
|
8
8
|
* too (two's-complement `&` already lands in `[0, cap)`).
|
|
9
9
|
**/
|
|
10
|
-
pub struct Set<T: Hashable + Equatable> {
|
|
10
|
+
pub mv struct Set<T: Hashable + Equatable> {
|
|
11
11
|
var length = 0
|
|
12
12
|
var slots = Buffer<T>()
|
|
13
13
|
var used = Buffer<int>()
|
|
14
14
|
|
|
15
|
-
pub func add = (ref self,
|
|
15
|
+
pub func add = (ref self, mv T value) {
|
|
16
16
|
var int cap = self.slots.cap
|
|
17
17
|
if cap == 0 {
|
|
18
18
|
cap = self.slots.alloc(8)
|
|
@@ -148,8 +148,8 @@ pub struct Set<T: Hashable + Equatable> {
|
|
|
148
148
|
}
|
|
149
149
|
|
|
150
150
|
func rehash = (ref self, int new_cap) {
|
|
151
|
-
var Buffer<T> old_slots =
|
|
152
|
-
var Buffer<int> old_used =
|
|
151
|
+
var Buffer<T> old_slots = mv self.slots swap Buffer<T>()
|
|
152
|
+
var Buffer<int> old_used = mv self.used swap Buffer<int>()
|
|
153
153
|
var int old_cap = old_slots.cap
|
|
154
154
|
|
|
155
155
|
self.slots.alloc(new_cap)
|
|
@@ -163,12 +163,12 @@ pub struct Set<T: Hashable + Equatable> {
|
|
|
163
163
|
// is owned by exactly one buffer (the new self) afterwards.
|
|
164
164
|
// load_T would leave the old slot referencing the same class
|
|
165
165
|
// pointer — a double-free when old_slots is destroyed. The
|
|
166
|
-
// result is bound to a local so
|
|
166
|
+
// result is bound to a local so a mv-element copy (e.g. a
|
|
167
167
|
// `Buffer<string>` slot, which store_T strdup's) is freed here
|
|
168
168
|
// once the new buffer has made its own copy — passing it inline
|
|
169
169
|
// would orphan the move_T result.
|
|
170
170
|
var T v = old_slots.move(i)
|
|
171
|
-
self.add(
|
|
171
|
+
self.add(mv v)
|
|
172
172
|
}
|
|
173
173
|
}
|
|
174
174
|
}
|
package/core/System/Spawnable.nm
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
// Spawnable — the trait role of a deferred-work LAUNCHER (the C# shape;
|
|
2
|
-
// see docs/ASYNC.md, "Design decisions"). A Spawnable
|
|
3
|
-
// (the construction special form) and its `start` submits it,
|
|
4
|
-
// library-owned `Task<T>` handle — so the await half is
|
|
5
|
-
// return type and each type carries exactly one role:
|
|
6
|
-
// are spawnable, `Task<T>` is awaitable.
|
|
7
|
-
// `wait` does not mention T);
|
|
8
|
-
// return type does.
|
|
2
|
+
// see docs/ASYNC.md, "Design decisions"). A Spawnable type packs a deferred
|
|
3
|
+
// unit of work (the construction special form) and its `start` submits it,
|
|
4
|
+
// yielding the library-owned `Task<T>` handle — so the await half is
|
|
5
|
+
// guaranteed by the return type and each type carries exactly one role:
|
|
6
|
+
// `Thread<T>`/`Fiber<T>` are spawnable, `Task<T>` is awaitable.
|
|
7
|
+
// `Awaitable` stays non-generic (its `wait` does not mention T);
|
|
8
|
+
// `Spawnable` is generic because `start`'s return type does.
|
|
9
9
|
//
|
|
10
10
|
// `detach` is the daemon role: run the work unjoinable, statement only.
|
|
11
11
|
|
|
12
12
|
/**
|
|
13
|
-
* A
|
|
13
|
+
* A type that can launch a deferred call and hand back its Task<T> handle
|
|
14
14
|
**/
|
|
15
15
|
pub trait Spawnable<T> {
|
|
16
|
-
func start = (ref self,
|
|
16
|
+
func start = (ref self, mv out Task<T>)
|
|
17
17
|
func detach = (ref self)
|
|
18
18
|
}
|
|
@@ -56,10 +56,9 @@ pub struct File {
|
|
|
56
56
|
case err == 17 {
|
|
57
57
|
return FileError.already_exists
|
|
58
58
|
}
|
|
59
|
-
|
|
59
|
+
} else {
|
|
60
60
|
return FileError.other
|
|
61
61
|
}
|
|
62
|
-
}
|
|
63
62
|
}
|
|
64
63
|
|
|
65
64
|
// Open the file at `path` with a C mode string ("r", "w", "a", …).
|
|
@@ -157,9 +156,9 @@ pub struct File {
|
|
|
157
156
|
}
|
|
158
157
|
|
|
159
158
|
// Read every byte from the current position to EOF and return it. Sets
|
|
160
|
-
// `eof` and `error`. Declared `
|
|
159
|
+
// `eof` and `error`. Declared `mv out string`: the raw body mallocs a
|
|
161
160
|
// fresh buffer and hands ownership to the caller.
|
|
162
|
-
func raw_read_all = (ref self,
|
|
161
|
+
func raw_read_all = (ref self, mv out string) {
|
|
163
162
|
```
|
|
164
163
|
#arch: c
|
|
165
164
|
FILE *f = (FILE*)(unsigned long long)self->handle;
|
|
@@ -272,8 +271,8 @@ pub struct File {
|
|
|
272
271
|
|
|
273
272
|
// Read up to the next '\n' (the newline is not included). Sets `eof`
|
|
274
273
|
// when the end of the file is reached and `error` on failure. The raw
|
|
275
|
-
// body mallocs a fresh buffer — `
|
|
276
|
-
func raw_read_line = (ref self,
|
|
274
|
+
// body mallocs a fresh buffer — `mv out string` transfers it.
|
|
275
|
+
func raw_read_line = (ref self, mv out string) {
|
|
277
276
|
```
|
|
278
277
|
#arch: c
|
|
279
278
|
FILE *f = (FILE*)(unsigned long long)self->handle;
|
|
@@ -416,8 +415,8 @@ pub struct File {
|
|
|
416
415
|
|
|
417
416
|
// Read up to `size` bytes from the current position. Sets `eof` if fewer
|
|
418
417
|
// than `size` bytes remain and `error` on failure. The raw body mallocs a
|
|
419
|
-
// fresh buffer — `
|
|
420
|
-
func raw_read_chunk = (ref self, int size,
|
|
418
|
+
// fresh buffer — `mv out string` transfers it.
|
|
419
|
+
func raw_read_chunk = (ref self, int size, mv out string) {
|
|
421
420
|
```
|
|
422
421
|
#arch: c
|
|
423
422
|
FILE *f = (FILE*)(unsigned long long)self->handle;
|
|
@@ -590,7 +589,7 @@ pub struct File {
|
|
|
590
589
|
|
|
591
590
|
// (static) Write `data` to `path` (replacing any existing contents) in
|
|
592
591
|
// one open/write/close. A write failure is reported as `.error`, not
|
|
593
|
-
// silently swallowed (the `
|
|
592
|
+
// silently swallowed (the `checked` Result discard check forces this to
|
|
594
593
|
// be deliberate).
|
|
595
594
|
pub func write_all = (string path, string data, out Result<bool, FileError>) {
|
|
596
595
|
var Result<bool, FileError> result = .error(FileError.other)
|
|
@@ -48,10 +48,9 @@ pub struct Http {
|
|
|
48
48
|
case err == 3 {
|
|
49
49
|
return HttpError.connect
|
|
50
50
|
}
|
|
51
|
-
|
|
51
|
+
} else {
|
|
52
52
|
return HttpError.other
|
|
53
53
|
}
|
|
54
|
-
}
|
|
55
54
|
}
|
|
56
55
|
|
|
57
56
|
// Shared socket round-trip used by get/post. `method` is the request
|
|
@@ -59,7 +58,7 @@ pub struct Http {
|
|
|
59
58
|
// (sends `body` and the Content-* headers). Sets self->status (0 on
|
|
60
59
|
// failure) and self->error, and returns the response body (empty string
|
|
61
60
|
// on failure).
|
|
62
|
-
func raw_exchange = (ref self, string method, string url, string body,
|
|
61
|
+
func raw_exchange = (ref self, string method, string url, string body, mv out string) {
|
|
63
62
|
// Parse the URL: [http://]host[:port][/path]
|
|
64
63
|
var host_start = 0
|
|
65
64
|
if url.starts_with("http://") {
|
|
@@ -23,10 +23,15 @@
|
|
|
23
23
|
// linked companion on aarch64) — OS socket/DNS interop, where hand-written
|
|
24
24
|
// per-target assembly is not practical.
|
|
25
25
|
|
|
26
|
+
// Tcp is an OWNING STRUCT (STRUCT_PLAN_3 Phase R, tranche 3 — the shape
|
|
27
|
+
// menu): the fields are the fd and an error code — the fd is the handle, so
|
|
28
|
+
// the value is movable and `#destroy` closes it. A moved Tcp transfers the
|
|
29
|
+
// socket; there is no aliasing copy to double-close.
|
|
30
|
+
|
|
26
31
|
/**
|
|
27
32
|
* A non-blocking TCP socket whose waits park the calling fiber
|
|
28
33
|
**/
|
|
29
|
-
pub
|
|
34
|
+
pub mv struct Tcp {
|
|
30
35
|
// The underlying file descriptor, -1 when closed/failed.
|
|
31
36
|
pub var int fd = -1
|
|
32
37
|
// 0 = ok; 1 = DNS, 2 = socket, 3 = connect, 4 = listen, 5 = closed.
|
|
@@ -64,7 +69,7 @@ pub class Tcp: Sendable {
|
|
|
64
69
|
// ---- listening ----
|
|
65
70
|
|
|
66
71
|
// Create a listening socket bound to `port` on all interfaces.
|
|
67
|
-
pub func listen = (int port, int backlog,
|
|
72
|
+
pub func listen = (int port, int backlog, mv out Tcp) {
|
|
68
73
|
var int handle = Tcp.listen_fd(port, backlog)
|
|
69
74
|
var t = Tcp(handle)
|
|
70
75
|
if handle < 0 {
|
|
@@ -76,7 +81,7 @@ pub class Tcp: Sendable {
|
|
|
76
81
|
// Accept the next connection, parking the fiber while the backlog is
|
|
77
82
|
// empty. The returned socket is -1 if the listener was cancelled or
|
|
78
83
|
// failed.
|
|
79
|
-
pub func accept = (ref self,
|
|
84
|
+
pub func accept = (ref self, mv out Tcp) {
|
|
80
85
|
var int handle = Tcp.accept_fd(self.fd)
|
|
81
86
|
var t = Tcp(handle)
|
|
82
87
|
if handle < 0 {
|
|
@@ -88,7 +93,7 @@ pub class Tcp: Sendable {
|
|
|
88
93
|
// ---- connecting ----
|
|
89
94
|
|
|
90
95
|
// Connect to `host`:`port`. Check `fd >= 0` (or `error == 0`) for success.
|
|
91
|
-
pub func connect = (string host, int port,
|
|
96
|
+
pub func connect = (string host, int port, mv out Tcp) {
|
|
92
97
|
var int handle = Tcp.socket_fd()
|
|
93
98
|
if handle < 0 {
|
|
94
99
|
var bad = Tcp(-1)
|
|
@@ -115,12 +120,12 @@ pub class Tcp: Sendable {
|
|
|
115
120
|
|
|
116
121
|
// Receive up to `max` bytes. Parks the fiber until data arrives; returns
|
|
117
122
|
// the empty string at end-of-stream, on error, or when cancelled.
|
|
118
|
-
pub func recv = (ref self, int max,
|
|
123
|
+
pub func recv = (ref self, int max, mv out string) {
|
|
119
124
|
return Tcp.recv_some(self.fd, max)
|
|
120
125
|
}
|
|
121
126
|
|
|
122
127
|
// Receive until the peer closes (how Connection: close HTTP works).
|
|
123
|
-
pub func recv_all = (ref self,
|
|
128
|
+
pub func recv_all = (ref self, mv out string) {
|
|
124
129
|
return Tcp.recv_until_close(self.fd)
|
|
125
130
|
}
|
|
126
131
|
|
|
@@ -326,7 +331,7 @@ pub class Tcp: Sendable {
|
|
|
326
331
|
```
|
|
327
332
|
}
|
|
328
333
|
|
|
329
|
-
func recv_some = (int handle, int max,
|
|
334
|
+
func recv_some = (int handle, int max, mv out string) {
|
|
330
335
|
```
|
|
331
336
|
#arch: c
|
|
332
337
|
long cap = max > 0 ? max : 1;
|
|
@@ -375,7 +380,7 @@ pub class Tcp: Sendable {
|
|
|
375
380
|
```
|
|
376
381
|
}
|
|
377
382
|
|
|
378
|
-
func recv_until_close = (int handle,
|
|
383
|
+
func recv_until_close = (int handle, mv out string) {
|
|
379
384
|
```
|
|
380
385
|
#arch: c
|
|
381
386
|
long cap = 4096, len = 0;
|
package/core/System/String.nm
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// FFI: the C library's heap-copy entry point (string.h). The adapter
|
|
2
2
|
// marshals the fat string to the thin char* the C ABI expects; the string
|
|
3
3
|
// result is re-wrapped with its length.
|
|
4
|
-
|
|
4
|
+
foreign func strdup = (string s, mv out string)
|
|
5
5
|
|
|
6
6
|
// Raw memory externs — the allocation primitives every `unsafe` Nomen body
|
|
7
7
|
// across core (Buffer, StringBuilder, Array, ...) is built on. This file is
|
|
@@ -9,17 +9,20 @@ extern func strdup = (string s, move out string)
|
|
|
9
9
|
// every core file regardless of pull order. Free externs emit under an
|
|
10
10
|
// `extern_<name>` label that wraps the identically-named C symbol, so these
|
|
11
11
|
// can never collide with it (docs/CORE_RAW.md roadmap items 1+2).
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
12
|
+
foreign func calloc = (int count, int size, out uint64)
|
|
13
|
+
foreign func malloc = (int bytes, out uint64)
|
|
14
|
+
foreign func realloc = (uint64 address, int bytes, out uint64)
|
|
15
|
+
foreign func free = (uint64 address)
|
|
16
|
+
foreign func memcpy = (uint64 dst, uint64 src, int bytes, out uint64)
|
|
17
|
+
foreign func memset = (uint64 dst, int value, int bytes, out uint64)
|
|
18
18
|
|
|
19
19
|
/**
|
|
20
|
-
* A UTF-8 text string — a heap-owned, length-tracked sequence of bytes
|
|
20
|
+
* A UTF-8 text string — a heap-owned, length-tracked sequence of bytes.
|
|
21
|
+
* STRUCT_PLAN_3 D3: `string` is OWNING — the fat (ptr, len) pair owns its
|
|
22
|
+
* bytes, so bindings mv unless a copy is spelled (`.copy()`); `view string`
|
|
23
|
+
* is the cheap read-only passing form.
|
|
21
24
|
**/
|
|
22
|
-
pub struct string: Stringable, Hashable, Equatable {
|
|
25
|
+
pub mv struct string: Stringable, Hashable, Equatable {
|
|
23
26
|
pub func hash = (self, out uint) {
|
|
24
27
|
// djb2 over exactly self.length bytes — matches the byte count of
|
|
25
28
|
// owned strings and literals (views hash the viewed bytes only).
|
|
@@ -31,12 +34,19 @@ pub struct string: Stringable, Hashable, Equatable {
|
|
|
31
34
|
return h
|
|
32
35
|
}
|
|
33
36
|
|
|
34
|
-
//
|
|
37
|
+
// The uniform mv-type verb: a fresh, owned byte-exact copy of self.
|
|
38
|
+
// The deep-copy spelling the binding/assignment copy errors name — same
|
|
39
|
+
// allocation contract as to_string (fresh buffer, never an alias).
|
|
40
|
+
pub func copy = (self, mv out string) {
|
|
41
|
+
return self.to_string()
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Returns an OWNED byte-exact copy of self (`mv out string`). Fresh
|
|
35
45
|
// allocation, never an alias of self's storage — the result can outlive
|
|
36
46
|
// the receiver (e.g. escape a match branch that reclaims the scrutinee
|
|
37
47
|
// temp). Copies by tracked length, so embedded NULs survive (an extern
|
|
38
48
|
// strdup boundary would re-synthesize length via strlen and truncate).
|
|
39
|
-
pub func to_string = (self,
|
|
49
|
+
pub func to_string = (self, mv out string) {
|
|
40
50
|
```
|
|
41
51
|
#arch: c
|
|
42
52
|
// Fat-string ABI: copy self.len bytes; no strlen anywhere.
|
|
@@ -90,7 +100,7 @@ pub struct string: Stringable, Hashable, Equatable {
|
|
|
90
100
|
panic("index out of range")
|
|
91
101
|
}
|
|
92
102
|
|
|
93
|
-
// A non-
|
|
103
|
+
// A non-mv slice [start, end) into self's buffer. Returns a `view
|
|
94
104
|
// string` (ptr, len) that borrows from self: it may not outlive self's
|
|
95
105
|
// scope and is invalidated if self is reassigned. Use .to_string() to
|
|
96
106
|
// materialize an owned copy.
|
|
@@ -178,9 +178,9 @@ pub struct StringBuilder {
|
|
|
178
178
|
// measure-and-restart shape: record `length()`, append a section, then
|
|
179
179
|
// `take_since(mark)` to measure it and re-emit decorated. `mark` clamps
|
|
180
180
|
// to [0, len]; the returned string is always an independent allocation.
|
|
181
|
-
// (`
|
|
181
|
+
// (`mv out string` — the raw body mallocs the result, so the caller
|
|
182
182
|
// owns it by signature, like `Console.read_line`.)
|
|
183
|
-
pub func take_since = (ref self, int mark,
|
|
183
|
+
pub func take_since = (ref self, int mark, mv out string) {
|
|
184
184
|
```
|
|
185
185
|
#arch: c
|
|
186
186
|
int start = mark;
|