nomen-lang 0.3.0 → 0.5.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.
Files changed (50) hide show
  1. package/NOMEN_AGENTS.md +7 -1
  2. package/core/System/Arena.nm +7 -7
  3. package/core/System/Awaitable.nm +21 -0
  4. package/core/System/BigInt.nm +5 -15
  5. package/core/System/Buffer.nm +140 -33
  6. package/core/System/Channel.nm +80 -29
  7. package/core/System/ClassBuffer.nm +89 -32
  8. package/core/System/Console.nm +4 -2
  9. package/core/System/Controls/Button.nm +4 -4
  10. package/core/System/Controls/CheckBox.nm +1 -1
  11. package/core/System/Controls/Text.nm +2 -2
  12. package/core/System/Controls/TextBox.nm +6 -6
  13. package/core/System/Controls/Window.nm +2 -2
  14. package/core/System/Fiber.nm +121 -0
  15. package/core/System/Graph.nm +4 -4
  16. package/core/System/LinkedList.nm +4 -4
  17. package/core/System/List.nm +6 -6
  18. package/core/System/Map.nm +30 -30
  19. package/core/System/Mutex.nm +57 -61
  20. package/core/System/Nursery.nm +10 -8
  21. package/core/System/Set.nm +24 -24
  22. package/core/System/Stream/Directory.nm +4 -4
  23. package/core/System/Stream/File.nm +19 -12
  24. package/core/System/Stream/Http.nm +83 -434
  25. package/core/System/Stream/Tcp.nm +441 -0
  26. package/core/System/String.nm +47 -18
  27. package/core/System/Task.nm +103 -4
  28. package/core/System/Text/JsonTree.nm +15 -15
  29. package/core/System/Thread.nm +83 -0
  30. package/core/System/bool.nm +2 -1
  31. package/core/System/char.nm +2 -1
  32. package/core/System/float.nm +2 -1
  33. package/core/System/float32.nm +2 -1
  34. package/core/System/float64.nm +2 -1
  35. package/core/System/int.nm +4 -2
  36. package/core/System/int16.nm +2 -1
  37. package/core/System/int32.nm +2 -1
  38. package/core/System/int64.nm +2 -1
  39. package/core/System/int8.nm +2 -1
  40. package/core/System/ufloat.nm +2 -1
  41. package/core/System/ufloat32.nm +2 -1
  42. package/core/System/ufloat64.nm +2 -1
  43. package/core/System/uint.nm +2 -1
  44. package/core/System/uint16.nm +2 -1
  45. package/core/System/uint32.nm +2 -1
  46. package/core/System/uint64.nm +2 -1
  47. package/core/System/uint8.nm +2 -1
  48. package/core/docs/System/BigInt.md +0 -1
  49. package/dist/index.mjs +20401 -13796
  50. package/package.json +1 -1
package/NOMEN_AGENTS.md CHANGED
@@ -128,7 +128,13 @@ const y = x + 1 // Error: 'x' is null
128
128
 
129
129
  ### Visibility
130
130
 
131
- `pub` exports; everything else is module-private. There is no `private` keyword.
131
+ `pub` exports. `internal` is visible only within the declaring library/module
132
+ (the System library uses it to hide implementation details). Everything else is
133
+ private to its declaring scope.
134
+
135
+ `readonly` is a field-write modifier, not a visibility: the field reads at its
136
+ declared visibility but can only be assigned inside its declaring struct/class
137
+ (and its `extend`s). `const` fields are immutable everywhere.
132
138
 
133
139
  ### Imports
134
140
 
@@ -76,8 +76,8 @@ pub struct Arena<T> {
76
76
  self.generations.grow_int(index + 1)
77
77
  self.generations.store_int(index, 0)
78
78
  }
79
- self.values.grow_T(index + 1)
80
- self.values.store_T(index, value)
79
+ self.values.grow(index + 1)
80
+ self.values.store(index, value)
81
81
  var ArenaRef<T> handle = ArenaRef<T>()
82
82
  handle.index = index
83
83
  handle.generation = self.generations.load_int(index)
@@ -92,7 +92,7 @@ pub struct Arena<T> {
92
92
  if !self.is_valid(handle) {
93
93
  panic("arena: free of a stale handle")
94
94
  }
95
- var T discarded = self.values.move_T(handle.index)
95
+ var T discarded = self.values.move(handle.index)
96
96
  self.generations.store_int(handle.index, handle.generation + 1)
97
97
  self.free_indices.grow_int(self.free_count + 1)
98
98
  self.free_indices.store_int(self.free_count, handle.index)
@@ -124,7 +124,7 @@ pub struct Arena<T> {
124
124
  if !self.is_valid(handle) {
125
125
  panic("arena: get of a stale handle")
126
126
  }
127
- return self.values.load_T(handle.index)
127
+ return self.values.load(handle.index)
128
128
  }
129
129
 
130
130
  /**
@@ -134,7 +134,7 @@ pub struct Arena<T> {
134
134
  if !self.is_valid(handle) {
135
135
  return fallback
136
136
  }
137
- return self.values.load_T(handle.index)
137
+ return self.values.load(handle.index)
138
138
  }
139
139
 
140
140
  /**
@@ -144,7 +144,7 @@ pub struct Arena<T> {
144
144
  if !self.is_valid(handle) {
145
145
  panic("arena: set through a stale handle")
146
146
  }
147
- self.values.replace_T(handle.index, value)
147
+ self.values.replace(handle.index, value)
148
148
  }
149
149
 
150
150
  /**
@@ -161,6 +161,6 @@ pub struct Arena<T> {
161
161
  * generation-check; callers own the index bookkeeping.
162
162
  **/
163
163
  pub func get_index = (self, int index: index >= 0 && index < self.count, out T) {
164
- return self.values.load_T(index)
164
+ return self.values.load(index)
165
165
  }
166
166
  }
@@ -0,0 +1,21 @@
1
+ // Awaitable — the consumption side of the async model (ASYNC.md,
2
+ // "Awaitable trait"). Park-flavored by design: `wait` MAY park the current
3
+ // execution context (inside a fiber it parks the fiber and frees its
4
+ // worker; on a raw thread it blocks). A Rust-style poll/Waker trait is
5
+ // deliberately rejected — it would smuggle the state-machine transform back
6
+ // in through the trait definition.
7
+ //
8
+ // `Task<T>` is the conformer: `Thread(...).start()` and `Fiber(...).start()`
9
+ // both yield one, so a generic helper taking `Awaitable` waits on either.
10
+ // The trait is deliberately NOT the place for must-start semantics —
11
+ // start-optional lifecycles are legitimate for user primitives; must-start
12
+ // is a per-struct `#destroy` contract (see Thread.nm / Fiber.nm and
13
+ // ASYNC.md).
14
+
15
+ /**
16
+ * Something whose completion can be waited on (may park the current context)
17
+ **/
18
+ pub trait Awaitable {
19
+ func wait = (ref self) {
20
+ }
21
+ }
@@ -6,7 +6,10 @@ pub struct BigInt {
6
6
  var len = 0
7
7
  var digits = Buffer<int>()
8
8
 
9
- pub func new = (ref self, int val, out BigInt) {
9
+ pub func #init = (ref self) {
10
+ }
11
+
12
+ pub func #init = (ref self, int val) {
10
13
  self.sign = 1
11
14
  var int v = val
12
15
  if v < 0 {
@@ -17,7 +20,6 @@ pub struct BigInt {
17
20
  self.digits.zero_int(self.digits.cap)
18
21
  self.digits.store_int(0, v)
19
22
  self.len = 1
20
- return self
21
23
  }
22
24
 
23
25
  // Per-limb get/set stay raw: they are `inline` and splice into the limb
@@ -528,20 +530,8 @@ pub struct BigInt {
528
530
  }
529
531
  self.len = self.len - 1
530
532
  }
531
-
532
- a0.digits.destroy()
533
- a1.digits.destroy()
534
- b0.digits.destroy()
535
- b1.digits.destroy()
536
- z0.digits.destroy()
537
- z2.digits.destroy()
538
- aa.digits.destroy()
539
- bb.digits.destroy()
540
- z1.digits.destroy()
541
- s0.digits.destroy()
542
- s1.digits.destroy()
543
- s2.digits.destroy()
544
533
  }
534
+
545
535
  // self = quotient, a = dividend, b = divisor, remainder = remainder
546
536
  // Uses remainder's internal buffer as working space
547
537
  pub func div_to = (ref self, BigInt a, BigInt b, ref BigInt remainder) {
@@ -1,25 +1,35 @@
1
1
  // Buffer<T>: a flat buffer of value slots of type T. The value counterpart to
2
2
  // ClassBuffer<T>: no per-element freeing, store_int unconstrained. When T is a
3
3
  // class, the monomorphizer rewrites a Buffer<T> field to ClassBuffer<T>.
4
+ //
5
+ // Public API is the size-aware family (`alloc`/`grow`/`load`/`replace`/
6
+ // `move`/`modify`/`shift`/`slice` plus the readonly `cap`). `replace` is the
7
+ // public write — it reclaims the displaced element, so it is correct on both
8
+ // fresh and occupied slots. `store` (which assumes a fresh slot and leaks on
9
+ // overwrite), `zero`, the fixed-width `*_u32`/`*_int`/`*_float` primitives,
10
+ // and the raw `data` pointer are `internal` and reserved for the System
11
+ // containers.
4
12
 
5
13
  /**
6
14
  * A flat, low-level buffer of value slots of type T — the backing store for arrays and collections
7
15
  **/
8
16
  pub struct Buffer<T> {
9
- var uint64 data = 0
10
- var cap = 0
17
+ internal var uint64 data = 0
18
+ // Publicly readable capacity (`i < self.cap` guards every accessor), but
19
+ // only Buffer's own methods may grow it — `readonly`.
20
+ readonly cap = 0
11
21
 
12
22
  // Allocation / sizing primitives are `unsafe` Nomen single-sourced for
13
23
  // both backends. They run once per container op (never per element), so
14
24
  // the aarch64 inline-method ABI cost that keeps the per-limb load/store
15
25
  // primitives raw (see BigInt.nm) doesn't apply here.
16
- func alloc = (ref self, int size, out int: out >= size) {
26
+ internal func alloc_u32 = (ref self, int size, out int: out >= size) {
17
27
  self.cap = size
18
28
  self.data = calloc(size, 4)
19
29
  return self.cap
20
30
  }
21
31
 
22
- func grow = (ref self, int needed, out int: out >= needed) {
32
+ internal func grow_u32 = (ref self, int needed, out int: out >= needed) {
23
33
  if self.cap >= needed {
24
34
  return self.cap
25
35
  }
@@ -34,11 +44,11 @@ pub struct Buffer<T> {
34
44
  return self.cap
35
45
  }
36
46
 
37
- func zero = (ref self, int len) {
47
+ internal func zero_u32 = (ref self, int len) {
38
48
  memset(self.data, 0, len * 4)
39
49
  }
40
50
 
41
- inline func load = (self, int i: i >= 0 && i < self.cap, out uint32) {
51
+ internal inline func load_u32 = (self, int i: i >= 0 && i < self.cap, out uint32) {
42
52
  ```
43
53
  #arch: c
44
54
  return ((unsigned int*)(unsigned long long)self->data)[i];
@@ -53,7 +63,7 @@ pub struct Buffer<T> {
53
63
  ```
54
64
  }
55
65
 
56
- inline func store = (ref self, int i: i >= 0 && i < self.cap, uint32 val) {
66
+ internal inline func store_u32 = (ref self, int i: i >= 0 && i < self.cap, uint32 val) {
57
67
  ```
58
68
  #arch: c
59
69
  ((unsigned int*)(unsigned long long)self->data)[i] = val;
@@ -67,7 +77,7 @@ pub struct Buffer<T> {
67
77
  ```
68
78
  }
69
79
 
70
- inline func store_or = (ref self, int i: i >= 0 && i < self.cap, uint32 val) {
80
+ internal inline func store_or_u32 = (ref self, int i: i >= 0 && i < self.cap, uint32 val) {
71
81
  ```
72
82
  #arch: c
73
83
  ((unsigned int*)(unsigned long long)self->data)[i] |= val;
@@ -83,13 +93,13 @@ pub struct Buffer<T> {
83
93
  ```
84
94
  }
85
95
 
86
- func alloc_int = (ref self, int size, out int: out >= size) {
96
+ internal func alloc_int = (ref self, int size, out int: out >= size) {
87
97
  self.cap = size
88
98
  self.data = calloc(size, 8)
89
99
  return self.cap
90
100
  }
91
101
 
92
- func grow_int = (ref self, int needed, out int: out >= needed) {
102
+ internal func grow_int = (ref self, int needed, out int: out >= needed) {
93
103
  if self.cap >= needed {
94
104
  return self.cap
95
105
  }
@@ -104,7 +114,7 @@ pub struct Buffer<T> {
104
114
  return self.cap
105
115
  }
106
116
 
107
- inline func load_int = (self, int i: i >= 0 && i < self.cap, out int) {
117
+ internal inline func load_int = (self, int i: i >= 0 && i < self.cap, out int) {
108
118
  ```
109
119
  #arch: c
110
120
  return ((long*)(unsigned long long)self->data)[i];
@@ -118,7 +128,7 @@ pub struct Buffer<T> {
118
128
  ```
119
129
  }
120
130
 
121
- inline func store_int = (ref self, int i: i >= 0 && i < self.cap, int val) {
131
+ internal inline func store_int = (ref self, int i: i >= 0 && i < self.cap, int val) {
122
132
  ```
123
133
  #arch: c
124
134
  ((long*)(unsigned long long)self->data)[i] = val;
@@ -136,7 +146,7 @@ pub struct Buffer<T> {
136
146
  // the ownership-extracting primitive (used by e.g. List.pop) — unlike
137
147
  // load_int (a borrow read), it relinquishes the slot so the buffer no
138
148
  // longer owns the value.
139
- inline func move_int = (ref self, int i: i >= 0 && i < self.cap, out int) {
149
+ internal inline func move_int = (ref self, int i: i >= 0 && i < self.cap, out int) {
140
150
  ```
141
151
  #arch: c
142
152
  long *slots = (long*)(unsigned long long)self->data;
@@ -157,7 +167,7 @@ pub struct Buffer<T> {
157
167
  // Store into a slot, freeing the previous value when the buffer holds
158
168
  // owned class pointers (has_class_refs). For non-class buffers this is a
159
169
  // plain store, so it is safe to use anywhere store_int would be.
160
- inline func replace_int = (ref self, int i: i >= 0 && i < self.cap, int val) {
170
+ internal inline func replace_int = (ref self, int i: i >= 0 && i < self.cap, int val) {
161
171
  ```
162
172
  #arch: c
163
173
  ((long*)(unsigned long long)self->data)[i] = val;
@@ -171,7 +181,7 @@ pub struct Buffer<T> {
171
181
  ```
172
182
  }
173
183
 
174
- inline func zero_int = (ref self, int len) {
184
+ internal inline func zero_int = (ref self, int len) {
175
185
  memset(self.data, 0, len * 8)
176
186
  }
177
187
 
@@ -180,13 +190,13 @@ pub struct Buffer<T> {
180
190
  // correctly. Classes route to ClassBuffer<T> (per-element destroy), so T
181
191
  // reaching here is always a value type (primitive or struct).
182
192
 
183
- func alloc_T = (ref self, int size, out int: out >= size) {
193
+ func alloc = (ref self, int size, out int: out >= size) {
184
194
  self.cap = size
185
195
  self.data = calloc(size, T_SIZE)
186
196
  return self.cap
187
197
  }
188
198
 
189
- func grow_T = (ref self, int needed, out int: out >= needed) {
199
+ func grow = (ref self, int needed, out int: out >= needed) {
190
200
  if self.cap >= needed {
191
201
  return self.cap
192
202
  }
@@ -205,7 +215,7 @@ pub struct Buffer<T> {
205
215
  // call sites — the load/store pair behind every container `.at`/`set` is
206
216
  // the hottest path in data-heavy code, and the naked-inline path keeps it
207
217
  // to a handful of instructions with no call overhead.
208
- inline func load_T = (self, int i: i >= 0 && i < self.cap, out T) {
218
+ inline func load = (self, int i: i >= 0 && i < self.cap, out T) {
209
219
  ```
210
220
  #arch: c
211
221
  return ((T*)(unsigned long long)self->data)[i];
@@ -249,12 +259,14 @@ pub struct Buffer<T> {
249
259
  }
250
260
 
251
261
  // Store `val` into slot `i`, which MUST be fresh (calloc'd, or zeroed by
252
- // move_T). For an owning T (string, or a struct with string fields) the
262
+ // move). For an owning T (string, or a struct with string fields) the
253
263
  // specialised body deep-copies the incoming value but does NOT free the
254
- // slot's previous occupant — a second `store_T` at an occupied index
255
- // leaks it. To overwrite a live slot use replace_T (frees the displaced
264
+ // slot's previous occupant — a second `store` at an occupied index
265
+ // leaks it. To overwrite a live slot use replace (frees the displaced
256
266
  // value) — this is the primitive every container's `set` uses.
257
- inline func store_T = (ref self, int i: i >= 0 && i < self.cap, T val) {
267
+ // Internal: assumes a FRESH slot (see the contract comment). The public
268
+ // write is `replace`, which is correct on fresh and occupied slots alike.
269
+ internal inline func store = (ref self, int i: i >= 0 && i < self.cap, T val) {
258
270
  ```
259
271
  #arch: c
260
272
  ((T*)(unsigned long long)self->data)[i] = val;
@@ -300,7 +312,7 @@ pub struct Buffer<T> {
300
312
  // the result is treated as OWNED by the borrow checker — the slot is
301
313
  // relinquished, so the caller is the sole remaining owner. The value
302
314
  // counterpart of ClassBuffer.move_int — used by List.pop for any value T.
303
- inline func move_T = (ref self, int i: i >= 0 && i < self.cap, move out T) {
315
+ inline func move = (ref self, int i: i >= 0 && i < self.cap, move out T) {
304
316
  ```
305
317
  #arch: c
306
318
  T* _slots = (T*)(unsigned long long)self->data;
@@ -356,14 +368,108 @@ pub struct Buffer<T> {
356
368
  ```
357
369
  }
358
370
 
371
+ // Apply `f` to slot `i` in place: the safe way to do a load→modify→store
372
+ // round-trip on a live slot. `f` receives the current value as a borrow
373
+ // (by value) and returns the replacement; the primitive itself handles
374
+ // ownership — the displaced value is freed, and a returned field that
375
+ // aliases the slot's own copy (the round-trip case) is kept, not freed or
376
+ // re-copied. Unlike store this never leaks on overwrite, and unlike
377
+ // replace it is safe to derive the new value from the old one. The
378
+ // returned struct's owning fields must be fresh, null, or identical to
379
+ // the corresponding input fields (no cross-field aliasing). For owning
380
+ // elements (string / structs with string fields) the build phase replaces
381
+ // this body with a specialized one (see owning_buffer_specialize.ts);
382
+ // this raw form is correct for trivially-copyable elements only. NOT
383
+ // `inline`: the body calls through the fn pointer, so splicing the raw
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) {
386
+ ```
387
+ #arch: c
388
+ ((T*)(unsigned long long)self->data)[i] = ((T (*)(void *, T))f->code)(f->env, ((T*)(unsigned long long)self->data)[i]);
389
+ ```
390
+ ```
391
+ #arch: aarch64
392
+ // x19 = self, x1 = i, x2 = f (a closure descriptor: { code, env,
393
+ // owned } — the call loads both words and passes env first, shifting
394
+ // the value argument to x1). Scalar elements round-trip through x1
395
+ // (width-matched); larger trivially-copyable structs pass the slot
396
+ // address and an sret pointer (x8) — the fn writes the replacement
397
+ // straight into the slot from a stack-stage copy of the old value.
398
+ stp x20, x21, [sp, #-16]!
399
+ stp x22, x23, [sp, #-16]!
400
+ stp x24, x25, [sp, #-16]!
401
+ mov x22, x2
402
+ ldr x9, [x19, #8]
403
+ mov x3, #T_SIZE
404
+ madd x20, x1, x3, xzr
405
+ add x20, x20, x9
406
+ ldr x24, [x22]
407
+ ldr x0, [x22, #8]
408
+ cmp x3, #8
409
+ b.gt .Lbuffer_modify_T_big
410
+ cmp x3, #1
411
+ b.eq .Lbuffer_modify_T_ld1
412
+ cmp x3, #2
413
+ b.eq .Lbuffer_modify_T_ld2
414
+ cmp x3, #4
415
+ b.eq .Lbuffer_modify_T_ld4
416
+ ldr x1, [x20]
417
+ b .Lbuffer_modify_T_call
418
+ .Lbuffer_modify_T_ld1:
419
+ ldrb w1, [x20]
420
+ b .Lbuffer_modify_T_call
421
+ .Lbuffer_modify_T_ld2:
422
+ ldrh w1, [x20]
423
+ b .Lbuffer_modify_T_call
424
+ .Lbuffer_modify_T_ld4:
425
+ ldr w1, [x20]
426
+ .Lbuffer_modify_T_call:
427
+ blr x24
428
+ cmp x3, #1
429
+ b.eq .Lbuffer_modify_T_st1
430
+ cmp x3, #2
431
+ b.eq .Lbuffer_modify_T_st2
432
+ cmp x3, #4
433
+ b.eq .Lbuffer_modify_T_st4
434
+ str x0, [x20]
435
+ b .Lbuffer_modify_T_end
436
+ .Lbuffer_modify_T_st1:
437
+ strb w0, [x20]
438
+ b .Lbuffer_modify_T_end
439
+ .Lbuffer_modify_T_st2:
440
+ strh w0, [x20]
441
+ b .Lbuffer_modify_T_end
442
+ .Lbuffer_modify_T_st4:
443
+ str w0, [x20]
444
+ b .Lbuffer_modify_T_end
445
+ .Lbuffer_modify_T_big:
446
+ add x23, x3, #15
447
+ bic x23, x23, #15
448
+ sub sp, sp, x23
449
+ mov x0, sp
450
+ mov x1, x20
451
+ mov x2, x3
452
+ bl _memcpy
453
+ ldr x0, [x22, #8]
454
+ mov x1, sp
455
+ mov x8, x20
456
+ blr x24
457
+ add sp, sp, x23
458
+ .Lbuffer_modify_T_end:
459
+ ldp x24, x25, [sp], #16
460
+ ldp x22, x23, [sp], #16
461
+ ldp x20, x21, [sp], #16
462
+ ```
463
+ }
464
+
359
465
  // Store into a T_SIZE-sized slot, overwriting the previous value. For
360
466
  // trivially-destructible value structs this is a plain overwrite. For
361
467
  // owning value structs (with string fields), the build phase replaces this
362
468
  // body with a specialised version that calls T_destroy on the old slot
363
469
  // value, then deep-copies (strdup per string field). See
364
- // owning_buffer_specialize.ts (both backends). ClassBuffer.replace_T
470
+ // owning_buffer_specialize.ts (both backends). ClassBuffer.replace
365
471
  // destroys+frees class slots soundly.
366
- inline func replace_T = (ref self, int i: i >= 0 && i < self.cap, T val) {
472
+ inline func replace = (ref self, int i: i >= 0 && i < self.cap, T val) {
367
473
  ```
368
474
  #arch: c
369
475
  ((T*)(unsigned long long)self->data)[i] = val;
@@ -407,14 +513,14 @@ pub struct Buffer<T> {
407
513
  // Move slot src into slot dst: overwrite dst with src's bytes and zero
408
514
  // src, so exactly ONE slot owns the value afterwards. The
409
515
  // ownership-transferring primitive behind backward-shift deletion
410
- // (Map/Set.remove) — unlike store_T, which gives the slot its own deep
516
+ // (Map/Set.remove) — unlike store, which gives the slot its own deep
411
517
  // copy and leaves the source slot intact, a shift transfers the source's
412
518
  // heap pointers wholesale. For owning elements (string / value structs
413
519
  // with string fields) the build replaces this body with a specialized
414
520
  // version that also reclaims dst's previous value first (see
415
521
  // owning_buffer_specialize.ts); this raw form is correct for
416
522
  // trivially-destructible elements only.
417
- inline func shift_T = (ref self, int dst: dst >= 0 && dst < self.cap, int src: src >= 0 && src < self.cap) {
523
+ inline func shift = (ref self, int dst: dst >= 0 && dst < self.cap, int src: src >= 0 && src < self.cap) {
418
524
  ```
419
525
  #arch: c
420
526
  T* _slots = (T*)(unsigned long long)self->data;
@@ -481,7 +587,7 @@ pub struct Buffer<T> {
481
587
  // self's scope and is invalidated if self is reassigned. This is the single
482
588
  // primitive every other slice (Array<T>, List<T>, user containers) builds
483
589
  // on — higher layers just `return self.items.slice(start, end)`.
484
- func slice = (self, int start: start >= 0, int end: end >= start, out view T) {
590
+ func slice = (self, int start: start >= 0, int end: end >= start && end <= self.cap, out view T) {
485
591
  ```
486
592
  #arch: c
487
593
  nomen_view _r;
@@ -500,11 +606,12 @@ pub struct Buffer<T> {
500
606
  ```
501
607
  }
502
608
 
503
- inline func zero_T = (ref self, int len) {
609
+ // Internal: zeroes slots without reclaiming owning elements.
610
+ internal inline func zero = (ref self, int len) {
504
611
  memset(self.data, 0, len * T_SIZE)
505
612
  }
506
613
 
507
- inline func store_or_int = (ref self, int i: i >= 0 && i < self.cap, int val) {
614
+ internal inline func store_or_int = (ref self, int i: i >= 0 && i < self.cap, int val) {
508
615
  ```
509
616
  #arch: c
510
617
  ((long*)(unsigned long long)self->data)[i] |= val;
@@ -520,13 +627,13 @@ pub struct Buffer<T> {
520
627
  ```
521
628
  }
522
629
 
523
- func alloc_float = (ref self, int size, out int: out >= size) {
630
+ internal func alloc_float = (ref self, int size, out int: out >= size) {
524
631
  self.cap = size
525
632
  self.data = calloc(size, 8)
526
633
  return self.cap
527
634
  }
528
635
 
529
- inline func load_float = (self, int i: i >= 0 && i < self.cap, out float) {
636
+ internal inline func load_float = (self, int i: i >= 0 && i < self.cap, out float) {
530
637
  ```
531
638
  #arch: c
532
639
  return ((double*)(unsigned long long)self->data)[i];
@@ -540,7 +647,7 @@ pub struct Buffer<T> {
540
647
  ```
541
648
  }
542
649
 
543
- inline func store_float = (ref self, int i: i >= 0 && i < self.cap, float val) {
650
+ internal inline func store_float = (ref self, int i: i >= 0 && i < self.cap, float val) {
544
651
  ```
545
652
  #arch: c
546
653
  ((double*)(unsigned long long)self->data)[i] = val;