nomen-lang 0.5.0 → 0.6.1

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.
@@ -36,17 +36,17 @@ pub struct Arena<T> {
36
36
  // Slot payloads. T = value struct/primitive routes to Buffer<T>; T =
37
37
  // class/trait routes to ClassBuffer<T> (monomorphize rewrites the field),
38
38
  // so slot ownership follows the usual element rules.
39
- var Buffer<T> values = Buffer<T>()
39
+ var values = Buffer<T>()
40
40
  // Per-slot generation, bumped on every free. Slots are calloc'd, so a
41
41
  // fresh slot's generation is 0.
42
- var Buffer<int> generations = Buffer<int>()
42
+ var generations = Buffer<int>()
43
43
  // Freed slot indices available for reuse (LIFO free list). A raw Buffer
44
44
  // plus an explicit count: a `List<int>` field would need its own
45
45
  // monomorphization from inside a generic struct body.
46
- var Buffer<int> free_indices = Buffer<int>()
47
- var int free_count = 0
46
+ var free_indices = Buffer<int>()
47
+ var free_count = 0
48
48
  // High-water mark: every index < count has a slot (live or free).
49
- var int count = 0
49
+ var count = 0
50
50
 
51
51
  /**
52
52
  * A fresh arena with no slots.
@@ -78,7 +78,7 @@ pub struct Arena<T> {
78
78
  }
79
79
  self.values.grow(index + 1)
80
80
  self.values.store(index, value)
81
- var ArenaRef<T> handle = ArenaRef<T>()
81
+ var handle = ArenaRef<T>()
82
82
  handle.index = index
83
83
  handle.generation = self.generations.load_int(index)
84
84
  return handle
@@ -37,7 +37,7 @@ pub struct Buffer<T> {
37
37
  if new_cap == 0 {
38
38
  new_cap = 8
39
39
  }
40
- while new_cap < needed; new_cap *= 2 {}
40
+ while new_cap < needed; new_cap *= 2 { }
41
41
  self.data = realloc(self.data, new_cap * 4)
42
42
  memset(self.data + self.cap * 4, 0, (new_cap - self.cap) * 4)
43
43
  self.cap = new_cap
@@ -107,7 +107,7 @@ pub struct Buffer<T> {
107
107
  if new_cap == 0 {
108
108
  new_cap = 4
109
109
  }
110
- while new_cap < needed; new_cap *= 2 {}
110
+ while new_cap < needed; new_cap *= 2 { }
111
111
  self.data = realloc(self.data, new_cap * 8)
112
112
  memset(self.data + self.cap * 8, 0, (new_cap - self.cap) * 8)
113
113
  self.cap = new_cap
@@ -204,7 +204,7 @@ pub struct Buffer<T> {
204
204
  if new_cap == 0 {
205
205
  new_cap = 4
206
206
  }
207
- while new_cap < needed; new_cap *= 2 {}
207
+ while new_cap < needed; new_cap *= 2 { }
208
208
  self.data = realloc(self.data, new_cap * T_SIZE)
209
209
  memset(self.data + self.cap * T_SIZE, 0, (new_cap - self.cap) * T_SIZE)
210
210
  self.cap = new_cap
@@ -382,7 +382,7 @@ pub struct Buffer<T> {
382
382
  // this raw form is correct for trivially-copyable elements only. NOT
383
383
  // `inline`: the body calls through the fn pointer, so splicing the raw
384
384
  // block into a caller would bypass the per-element specializations.
385
- func modify = (ref self, int i: i >= 0 && i < self.cap, func (T, out T) f) {
385
+ func modify = (ref self, int i: i >= 0 && i < self.cap, func(T, out T) f) {
386
386
  ```
387
387
  #arch: c
388
388
  ((T*)(unsigned long long)self->data)[i] = ((T (*)(void *, T))f->code)(f->env, ((T*)(unsigned long long)self->data)[i]);
@@ -520,7 +520,11 @@ pub struct Buffer<T> {
520
520
  // version that also reclaims dst's previous value first (see
521
521
  // owning_buffer_specialize.ts); this raw form is correct for
522
522
  // trivially-destructible elements only.
523
- inline func shift = (ref self, int dst: dst >= 0 && dst < self.cap, int src: src >= 0 && src < self.cap) {
523
+ inline func shift = (
524
+ ref self,
525
+ int dst: dst >= 0 && dst < self.cap,
526
+ int src: src >= 0 && src < self.cap
527
+ ) {
524
528
  ```
525
529
  #arch: c
526
530
  T* _slots = (T*)(unsigned long long)self->data;
@@ -587,7 +591,12 @@ pub struct Buffer<T> {
587
591
  // self's scope and is invalidated if self is reassigned. This is the single
588
592
  // primitive every other slice (Array<T>, List<T>, user containers) builds
589
593
  // on — higher layers just `return self.items.slice(start, end)`.
590
- func slice = (self, int start: start >= 0, int end: end >= start && end <= self.cap, out view T) {
594
+ func slice = (
595
+ self,
596
+ int start: start >= 0,
597
+ int end: end >= start && end <= self.cap,
598
+ out view T
599
+ ) {
591
600
  ```
592
601
  #arch: c
593
602
  nomen_view _r;
@@ -180,6 +180,8 @@ pub class Channel: Sendable {
180
180
  str x2, [x19, #32] // tail = node
181
181
  ldr x0, [x19, #16] // not_empty_cv
182
182
  bl _pthread_cond_signal
183
+ add x0, x19, #40 // &self->waiters — wake parked fibers
184
+ bl ___nomen_fiber_waitq_wake
183
185
  ldr x0, [x19, #8] // self->mu
184
186
  bl _pthread_mutex_unlock
185
187
  add sp, sp, #32
@@ -37,7 +37,7 @@ pub struct ClassBuffer<T> {
37
37
  if new_cap == 0 {
38
38
  new_cap = 4
39
39
  }
40
- while new_cap < needed; new_cap *= 2 {}
40
+ while new_cap < needed; new_cap *= 2 { }
41
41
  self.data = realloc(self.data, new_cap * 8)
42
42
  memset(self.data + self.cap * 8, 0, (new_cap - self.cap) * 8)
43
43
  self.cap = new_cap
@@ -73,7 +73,7 @@ pub struct ClassBuffer<T> {
73
73
  if new_cap == 0 {
74
74
  new_cap = 4
75
75
  }
76
- while new_cap < needed; new_cap *= 2 {}
76
+ while new_cap < needed; new_cap *= 2 { }
77
77
  self.data = realloc(self.data, new_cap * 8)
78
78
  memset(self.data + self.cap * 8, 0, (new_cap - self.cap) * 8)
79
79
  self.cap = new_cap
@@ -150,7 +150,7 @@ pub struct ClassBuffer<T> {
150
150
  // unless `f` returned it. Storing the returned instance raw is sound:
151
151
  // the slot takes sole ownership and `f`'s return is not retained
152
152
  // elsewhere. NOT `inline`: the body calls through the fn pointer.
153
- func modify = (ref self, int i: i >= 0 && i < self.cap, func (T, out T) f) {
153
+ func modify = (ref self, int i: i >= 0 && i < self.cap, func(T, out T) f) {
154
154
  ```
155
155
  #arch: c
156
156
  long *slots = (long*)(unsigned long long)self->data;
@@ -299,7 +299,11 @@ pub struct ClassBuffer<T> {
299
299
  // instance afterwards. The class-buffer counterpart of Buffer.shift,
300
300
  // used by Map/Set.remove's backward-shift so shifting entries neither
301
301
  // duplicates nor orphans owned instances.
302
- func shift = (ref self, int dst: dst >= 0 && dst < self.cap, int src: src >= 0 && src < self.cap) {
302
+ func shift = (
303
+ ref self,
304
+ int dst: dst >= 0 && dst < self.cap,
305
+ int src: src >= 0 && src < self.cap
306
+ ) {
303
307
  ```
304
308
  #arch: c
305
309
  long *slots = (long*)(unsigned long long)self->data;
@@ -343,7 +347,12 @@ pub struct ClassBuffer<T> {
343
347
  // pointers, returned as a `view T` (T is a class, so each element is an
344
348
  // 8-byte pointer). Borrows from self — invalidated on reassignment. Mirrors
345
349
  // Buffer.slice; ClassBuffer stores 8-byte slots, so the element width is 8.
346
- func slice = (self, int start: start >= 0, int end: end >= start && end <= self.cap, out view T) {
350
+ func slice = (
351
+ self,
352
+ int start: start >= 0,
353
+ int end: end >= start && end <= self.cap,
354
+ out view T
355
+ ) {
347
356
  ```
348
357
  #arch: c
349
358
  nomen_view _r;
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * A push-button control that triggers an action when clicked
3
3
  **/
4
- pub class Button : Control {
4
+ pub class Button: Control {
5
5
  var uint64 handle = 0
6
6
 
7
7
  pub func #init = (self, Window window, string title) {
@@ -162,7 +162,7 @@ pub class Button : Control {
162
162
 
163
163
  pub func intrinsic_size = (self, out Size) {
164
164
  var [w, h] = native_intrinsic(self.handle)
165
- var Size s = Size()
165
+ var s = Size()
166
166
  s.width = w
167
167
  s.height = h
168
168
  return s
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * A toggle control with a title and checked/hidden state
3
3
  **/
4
- pub class CheckBox : Control {
4
+ pub class CheckBox: Control {
5
5
  var uint64 handle = 0
6
6
 
7
7
  pub func #init = (self, Window window) {
@@ -199,7 +199,7 @@ pub class CheckBox : Control {
199
199
  // ── Control trait conformance ──
200
200
  pub func intrinsic_size = (self, out Size) {
201
201
  var [w, h] = native_intrinsic(self.handle)
202
- var Size s = Size()
202
+ var s = Size()
203
203
  s.width = w
204
204
  s.height = h
205
205
  return s
@@ -248,7 +248,7 @@ pub func native_intrinsic = (uint64 handle, out [int, int]) {
248
248
  * so a `Container` can also be driven polymorphically as a `Control` (passed to
249
249
  * a `Control`-taking function, stored in a `ClassBuffer<Control>`, etc.).
250
250
  **/
251
- pub class Container : Control {
251
+ pub class Container: Control {
252
252
  var kinds = Buffer<int>()
253
253
  // Per-leaf requested size, stored as a (kind, value) pair per axis. The
254
254
  // kind is one of LEN_* (auto/fixed/percent/fill); the value is the pixel
@@ -1358,7 +1358,7 @@ pub class Container : Control {
1358
1358
  constraints.max_height,
1359
1359
  )
1360
1360
  var int h = self.rh.load_int(self.root)
1361
- var Size s = Size()
1361
+ var s = Size()
1362
1362
  s.width = w
1363
1363
  s.height = h
1364
1364
  return s
@@ -1371,7 +1371,7 @@ pub class Container : Control {
1371
1371
  pub func intrinsic_size = (self, out Size) {
1372
1372
  var int w = self.measure_node(self.root, 0, INF, 0, INF)
1373
1373
  var int h = self.rh.load_int(self.root)
1374
- var Size s = Size()
1374
+ var s = Size()
1375
1375
  s.width = w
1376
1376
  s.height = h
1377
1377
  return s
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * An editable single-line text input control
3
3
  **/
4
- pub class TextBox : Control {
4
+ pub class TextBox: Control {
5
5
  var uint64 handle = 0
6
6
 
7
7
  pub func #init = (self, Window window) {
@@ -203,7 +203,7 @@ pub class TextBox : Control {
203
203
  // ── Control trait conformance ──
204
204
  pub func intrinsic_size = (self, out Size) {
205
205
  var [w, h] = native_intrinsic(self.handle)
206
- var Size s = Size()
206
+ var s = Size()
207
207
  s.width = w
208
208
  s.height = h
209
209
  return s
@@ -23,15 +23,25 @@
23
23
  // calling thread and never starts worker threads — a cooperative,
24
24
  // single-threaded runtime for bare-metal targets.
25
25
  //
26
- // The constructor, `.start`, and `.start_on` are compiler-special-cased
27
- // (they need the per-site spawn/trampoline machinery), so they are NOT
28
- // regular methods declared here. The runtime (scheduler, context switch)
29
- // lives in the build's emitted companion C — see build_fiber_spawn.
26
+ // The constructor and `.start_on(buf)` are compiler-special-cased (they
27
+ // need the per-site spawn/trampoline machinery and the buffer's compile-time
28
+ // byte size); `.start()` is a regular method over the runtime seam — it
29
+ // reads the packed handles from the instance's fields and drives the
30
+ // scheduler. The runtime (scheduler, context switch) lives in the build's
31
+ // emitted companion C — see build_fiber_spawn.
32
+
33
+ // The launch surface's return type (ASYNC.md: the dependency is
34
+ // declared by the library file, not inferred from user-source tokens).
35
+ import Task
30
36
 
31
37
  /**
32
38
  * A stackful coroutine: lightweight, cooperatively scheduled, parks instead of blocking
33
39
  **/
34
- pub class Fiber<T> : Sendable {
40
+ pub class Fiber<T> : Sendable, Spawnable<T> {
41
+ // The construction hook (see Thread.nm): the deferred-call special form.
42
+ #spawn = () {
43
+ }
44
+
35
45
  // The packed task closure (a `struct nomen_closure *`); owned by this
36
46
  // value until start/start_on/nursery.start transfers it to the runtime.
37
47
  pub var uint64 task = 0
@@ -41,6 +51,76 @@ pub class Fiber<T> : Sendable {
41
51
  pub var uint64 future = 0
42
52
  // Must-start flag: set by .start() / .start_on(buf) / nursery.start.
43
53
  pub var started = false
54
+ // LEXICAL NURSERY CAPTURE (ASYNC.md): the tracking slots of the
55
+ // `async` block that lexically encloses the CONSTRUCTION, or 0 when the
56
+ // construction is outside any block. `.start()` registers the future
57
+ // through these stored pointers — registration follows the scope that
58
+ // created the deferred call, not the one that happens to start it. See
59
+ // Thread.nm's matching fields.
60
+ pub var uint64 nursery_futures = 0
61
+ pub var uint64 nursery_count = 0
62
+ pub var uint64 nursery_cap = 0
63
+
64
+ // Start the deferred call on the fiber scheduler and yield the Task<T>
65
+ // handle. Same shape as Thread.start: consume the machinery, register
66
+ // with the construction-time nursery (if captured), transfer the handles
67
+ // out of the instance (started; #destroy no-ops), return the handle.
68
+ // While the fiber waits, it parks and frees its worker instead of
69
+ // blocking it.
70
+ pub func start = (ref self, move out Task<T>) {
71
+ ```
72
+ #arch: c
73
+ struct nomen_future *_f = (struct nomen_future *)self->future;
74
+ _f->refs = self->nursery_futures ? 3 : 2;
75
+ __nomen_fiber_spawn((struct nomen_closure *)self->task, _f);
76
+ if (self->nursery_futures) {
77
+ __nomen_nursery_track((void **)self->nursery_futures, (int *)self->nursery_count, (int *)self->nursery_cap, _f);
78
+ }
79
+ ```
80
+ ```
81
+ #arch: aarch64
82
+ // x19 = self. f = self->future (#32); nursery_futures at #48.
83
+ ldr x0, [x19, #32]
84
+ ldr x1, [x19, #48]
85
+ mov w2, #2
86
+ cbz x1, .Lnomen_fstart_refs
87
+ mov w2, #3
88
+ .Lnomen_fstart_refs:
89
+ str w2, [x0, #116]
90
+ // __nomen_fiber_spawn(self->task, f)
91
+ ldr x0, [x19, #8]
92
+ ldr x1, [x19, #32]
93
+ bl ___nomen_fiber_spawn
94
+ // if (self->nursery_futures) __nomen_nursery_track(futures, count, cap, f)
95
+ ldr x0, [x19, #48]
96
+ cbz x0, .Lnomen_fstart_notrack
97
+ ldr x1, [x19, #56]
98
+ ldr x2, [x19, #64]
99
+ ldr x3, [x19, #32]
100
+ bl ___nomen_nursery_track
101
+ .Lnomen_fstart_notrack:
102
+ ```
103
+ var t = Task<T>()
104
+ t.result_slot = self.result_slot
105
+ t.cancel_flag = self.cancel_flag
106
+ t.future = self.future
107
+ // Transfer the handles out of the instance: the runtime owns
108
+ // everything now, and #destroy must not touch (or must-start-abort).
109
+ self.task = 0
110
+ self.future = 0
111
+ self.result_slot = 0
112
+ self.cancel_flag = 0
113
+ self.started = true
114
+ return t
115
+ }
116
+
117
+ // Run the deferred call fire-and-forget (the Spawnable daemon role).
118
+ // The fiber is launched exactly like start, but the handle is dropped
119
+ // immediately: the future's refs are released as the discarded Task is
120
+ // reclaimed, and the fiber completes into the void — nothing joins it.
121
+ pub func detach = (ref self) {
122
+ self.start()
123
+ }
44
124
 
45
125
  // Destroying an unstarted Fiber is a programming error (the wrapped
46
126
  // call would silently never run) — report it and abort. A started
@@ -7,7 +7,7 @@
7
7
  * A graph of values connected by edges
8
8
  **/
9
9
  pub struct Graph<T>: Enumerable {
10
- var Buffer<T> values = Buffer<T>()
10
+ var values = Buffer<T>()
11
11
  var head_edge = Buffer<int>()
12
12
  var edge_target = Buffer<int>()
13
13
  var edge_next = Buffer<int>()
@@ -7,7 +7,7 @@
7
7
  * A doubly-linked list of values
8
8
  **/
9
9
  pub struct LinkedList<T>: Enumerable {
10
- var Buffer<T> values = Buffer<T>()
10
+ var values = Buffer<T>()
11
11
  var nexts = Buffer<int>()
12
12
  var prevs = Buffer<int>()
13
13
  var int head = -1
@@ -3,7 +3,7 @@
3
3
  **/
4
4
  pub struct List<T>: Viewable {
5
5
  var length = 0
6
- var Buffer<T> items = Buffer<T>()
6
+ var items = Buffer<T>()
7
7
 
8
8
  pub func push = (ref self, move T value) {
9
9
  if self.length >= self.items.cap {
@@ -70,8 +70,8 @@ pub struct List<T>: Viewable {
70
70
  // never re-checked, so it can't rely on check-time call-arg hoisting for
71
71
  // struct element types.
72
72
  pub func copy = (self, out List<T>) {
73
- var List<T> dst = List<T>()
74
- var int i = 0
73
+ var dst = List<T>()
74
+ var i = 0
75
75
  while i < self.length {
76
76
  var T v = self.at(i)
77
77
  dst.push(v)
@@ -10,8 +10,8 @@
10
10
  **/
11
11
  pub struct Map<TK: Hashable + Equatable, TV> {
12
12
  var length = 0
13
- var Buffer<TK> keys = Buffer<TK>()
14
- var Buffer<TV> values = Buffer<TV>()
13
+ var keys = Buffer<TK>()
14
+ var values = Buffer<TV>()
15
15
  var used = Buffer<int>()
16
16
 
17
17
  // Variadic-tuple constructor: Map<string, int>(["a", 1], ["b", 2]) or
@@ -16,7 +16,7 @@
16
16
  pub class Mutex: Sendable {
17
17
  pub var uint64 handle = 0
18
18
 
19
- pub func #init = (self) {
19
+ pub func #init = (self) {
20
20
  ```
21
21
  #arch: c
22
22
  self->handle = (unsigned long long)__nomen_mutex_create();
@@ -26,9 +26,9 @@ pub func #init = (self) {
26
26
  bl ___nomen_mutex_create
27
27
  str x0, [x19, #8]
28
28
  ```
29
- }
29
+ }
30
30
 
31
- pub func lock = (self) {
31
+ pub func lock = (self) {
32
32
  ```
33
33
  #arch: c
34
34
  // Fibers park instead of blocking the worker (both models); other
@@ -40,9 +40,9 @@ pub func lock = (self) {
40
40
  ldr x0, [x19, #8]
41
41
  bl ___nomen_mutex_lock
42
42
  ```
43
- }
43
+ }
44
44
 
45
- pub func unlock = (self) {
45
+ pub func unlock = (self) {
46
46
  ```
47
47
  #arch: c
48
48
  __nomen_mutex_unlock_wake((void *)self->handle);
@@ -52,9 +52,9 @@ pub func unlock = (self) {
52
52
  ldr x0, [x19, #8]
53
53
  bl ___nomen_mutex_unlock_wake
54
54
  ```
55
- }
55
+ }
56
56
 
57
- pub func #destroy = () {
57
+ pub func #destroy = () {
58
58
  ```
59
59
  #arch: c
60
60
  if (self->handle) {
@@ -70,5 +70,5 @@ pub func #destroy = () {
70
70
  str xzr, [x19, #8]
71
71
  .Lmutex_destroy_end:
72
72
  ```
73
- }
73
+ }
74
74
  }
@@ -1,4 +1,4 @@
1
1
  pub enum Option<T> {
2
- case some(T value)
3
- case none
2
+ case some(T value)
3
+ case none
4
4
  }
@@ -0,0 +1,67 @@
1
+ // Random — a small, fast pseudo-random generator (splitmix64).
2
+ //
3
+ // Splitmix64 steps a 64-bit state by the golden ratio, then runs two
4
+ // multiply-xor rounds. Streams from nearby seeds are fully decorrelated
5
+ // (each seed is its own stream), so `Random()` — seeded from the wall
6
+ // clock — is safe to construct repeatedly in quick succession (e.g. one
7
+ // per spawned task, all starting within the same microsecond).
8
+ //
9
+ // Not cryptographically secure; `below`/`range` have slight modulo bias
10
+ // for very large bounds.
11
+ //
12
+ // var Random rng = Random()
13
+ // var uint64 roll = rng.below(6) // 0..5
14
+ // var uint64 ms = rng.range(1000, 10000) // 1000..10000, inclusive
15
+ //
16
+ import Time
17
+
18
+ /**
19
+ * A fast splitmix64 pseudo-random number generator
20
+ **/
21
+ pub class Random {
22
+ // The raw 64-bit generator state (seeded from the wall clock by the
23
+ // no-arg constructor, or an explicit seed for reproducible sequences).
24
+ pub var uint64 state = 0
25
+
26
+ // Seed from the wall clock (nanoseconds since the epoch).
27
+ pub func #init = (self) {
28
+ self.state = Time.now_ns()
29
+ }
30
+
31
+ // Seed from an explicit value — reproducible sequences for tests.
32
+ pub func #init = (self, uint64 seed) {
33
+ self.state = seed
34
+ }
35
+
36
+ // The next 64-bit value (splitmix64: golden-ratio step, then two
37
+ // multiply-xor rounds). Pure Nomen — the 64-bit arithmetic, bitwise
38
+ // operators, and hex literals all lower directly. The aarch64 codegen is
39
+ // a little looser than a hand-written `#arch` body would be (constant
40
+ // materialization, field reloads, non-immediate shift counts); see
41
+ // FOLLOWUP.md if this ever needs to be hot.
42
+ pub func next = (ref self, out uint64) {
43
+ self.state = self.state + 0x9E3779B97F4A7C15
44
+ var uint64 z = self.state
45
+ z = (z ^ (z >> 30)) * 0xBF58476D1CE4E5B9
46
+ z = (z ^ (z >> 27)) * 0x94D049BB133111EB
47
+ return z ^ (z >> 31)
48
+ }
49
+
50
+ // The next value in [0, bound). A bound of 0 returns 0. Slight modulo
51
+ // bias for very large bounds — irrelevant at demo scale.
52
+ pub func below = (ref self, uint64 bound, out uint64) {
53
+ if bound == 0 {
54
+ return 0
55
+ }
56
+ return self.next() % bound
57
+ }
58
+
59
+ // The next value in [lo, hi], both ends inclusive. A hi <= lo
60
+ // returns lo.
61
+ pub func range = (ref self, uint64 lo, uint64 hi, out uint64) {
62
+ if hi <= lo {
63
+ return lo
64
+ }
65
+ return lo + self.below(hi - lo + 1)
66
+ }
67
+ }
@@ -1,4 +1,4 @@
1
1
  pub must_use enum Result<T, E> {
2
- case ok(T value)
3
- case error(E error)
2
+ case ok(T value)
3
+ case error(E error)
4
4
  }
@@ -9,7 +9,7 @@
9
9
  **/
10
10
  pub struct Set<T: Hashable + Equatable> {
11
11
  var length = 0
12
- var Buffer<T> slots = Buffer<T>()
12
+ var slots = Buffer<T>()
13
13
  var used = Buffer<int>()
14
14
 
15
15
  pub func add = (ref self, move T value) {
@@ -0,0 +1,18 @@
1
+ // Spawnable — the trait role of a deferred-work LAUNCHER (the C# shape;
2
+ // see docs/ASYNC.md, "Design decisions"). A Spawnable class packs a deferred unit of work
3
+ // (the construction special form) and its `start` submits it, yielding the
4
+ // library-owned `Task<T>` handle — so the await half is guaranteed by the
5
+ // return type and each type carries exactly one role: `Thread<T>`/`Fiber<T>`
6
+ // are spawnable, `Task<T>` is awaitable. `Awaitable` stays non-generic (its
7
+ // `wait` does not mention T); `Spawnable` is generic because `start`'s
8
+ // return type does.
9
+ //
10
+ // `detach` is the daemon role: run the work unjoinable, statement only.
11
+
12
+ /**
13
+ * A class that can launch a deferred call and hand back its Task<T> handle
14
+ **/
15
+ pub trait Spawnable<T> {
16
+ func start = (ref self, move out Task<T>)
17
+ func detach = (ref self)
18
+ }
@@ -39,7 +39,7 @@ pub struct File {
39
39
  pub var eof = false
40
40
  // errno of the last operation; 0 = success. Raw #arch bodies set it,
41
41
  // the Result-returning wrappers map it to FileError.
42
- var int error = 0
42
+ var error = 0
43
43
 
44
44
  // Maps an errno to its FileError case.
45
45
  func error_of = (int err, out FileError) {
@@ -569,7 +569,7 @@ pub struct File {
569
569
  // (static) Read the entire contents of `path` in one open/read/close.
570
570
  pub func read_all = (string path, out Result<string, FileError>) {
571
571
  var Result<string, FileError> result = .error(FileError.other)
572
- var File f = File()
572
+ var f = File()
573
573
  match f.open(path, "r") {
574
574
  case .ok(did) {
575
575
  match f.readAll() {
@@ -594,7 +594,7 @@ pub struct File {
594
594
  // be deliberate).
595
595
  pub func write_all = (string path, string data, out Result<bool, FileError>) {
596
596
  var Result<bool, FileError> result = .error(FileError.other)
597
- var File f = File()
597
+ var f = File()
598
598
  match f.open(path, "w") {
599
599
  case .ok(did) {
600
600
  match f.writeAll(data) {
@@ -28,13 +28,13 @@
28
28
  pub struct Http {
29
29
  // HTTP status code from the most recent request (e.g. 200). 0 when the
30
30
  // request failed (the `error` side of the get/post Result says why).
31
- pub var int status = 0
31
+ pub var status = 0
32
32
 
33
33
  // Internal failure code from the most recent request: 0 = success,
34
34
  // 1 = DNS resolution, 2 = socket creation, 3 = connect, 6 = send failed.
35
35
  // Mirrors Tcp's codes on the connect path; the Result-returning wrappers
36
36
  // map it to HttpError.
37
- var int error = 0
37
+ var error = 0
38
38
 
39
39
  // Maps the raw failure code to its HttpError case.
40
40
  func error_of = (int err, out HttpError) {
@@ -61,7 +61,7 @@ pub struct Http {
61
61
  // on failure).
62
62
  func raw_exchange = (ref self, string method, string url, string body, move out string) {
63
63
  // Parse the URL: [http://]host[:port][/path]
64
- var int host_start = 0
64
+ var host_start = 0
65
65
  if url.starts_with("http://") {
66
66
  host_start = 7
67
67
  }
@@ -77,13 +77,13 @@ pub struct Http {
77
77
  name_end = colon
78
78
  }
79
79
  }
80
- var int port = 80
80
+ var port = 80
81
81
  if name_end != host_end {
82
82
  var string port_text = url.substring(name_end + 1, host_end)
83
83
  port = int.parse(port_text)
84
84
  }
85
85
  var string host = url.substring(host_start, name_end)
86
- var string path = "/"
86
+ var path = "/"
87
87
  if slash >= 0 {
88
88
  path = url.substring(slash, url.length)
89
89
  }