Add standard library reference manual with per-module API docs
Create docs/manual/stdlib/ with 12 topic pages covering all stdlib modules (builtins, Option/Result, collections, iterators, math, strings, ranges, async runtime, networking, time, synchronization). Move scattered stdlib content from language manual pages into the dedicated stdlib section, replacing with concise summaries and links. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -4,10 +4,10 @@ This manual has been split into topic pages for easier navigation.
|
||||
|
||||
**[Go to the manual](manual/index.md)**
|
||||
|
||||
## Quick links
|
||||
## Language
|
||||
|
||||
- [Basics](manual/basics.md) -- variables, comments, strings, primitive types
|
||||
- [Type Declarations](manual/types.md) -- objects, tuples, ref objects, enums, standard library types
|
||||
- [Type Declarations](manual/types.md) -- objects, tuples, ref objects, enums
|
||||
- [Functions](manual/functions.md) -- functions, async, lambdas, closures, UFCS
|
||||
- [Control Flow](manual/control-flow.md) -- if/else, while, for, pattern matching, blocks
|
||||
- [Generics](manual/generics.md) -- parametric polymorphism, constraints, static parameters
|
||||
@@ -19,5 +19,19 @@ This manual has been split into topic pages for easier navigation.
|
||||
- [Compile-Time Features](manual/compile-time.md) -- `when`/`defined()`, CTFE, pragmas
|
||||
- [Modules](manual/modules.md) -- import/export, visibility, module execution
|
||||
- [C Interop](manual/c-interop.md) -- importc, exportc, C-compatible types, converters
|
||||
|
||||
## Standard Library
|
||||
|
||||
- **[Standard Library Reference](manual/stdlib/index.md)**
|
||||
- [Built-in Functions](manual/stdlib/builtins.md) -- print, panic, clone, sizeof, etc.
|
||||
- [Option and Result](manual/stdlib/types.md) -- Option[T], Result[T, E]
|
||||
- [Collections](manual/stdlib/collections.md) -- array, seq, deque
|
||||
- [Iterators](manual/stdlib/iterators.md) -- Generator, Iterator protocols
|
||||
- [Math](manual/stdlib/math.md) | [Strings](manual/stdlib/strings.md) | [Ranges](manual/stdlib/ranges.md)
|
||||
- [Async Runtime](manual/stdlib/async.md) | [Networking](manual/stdlib/net.md) | [Time](manual/stdlib/time.md)
|
||||
- [Synchronization](manual/stdlib/sync.md) -- Event, LIFOQueue, FIFOQueue
|
||||
|
||||
## Reference
|
||||
|
||||
- [Grammar](grammar.md)
|
||||
- [Bytecode](bytecode.md)
|
||||
|
||||
@@ -185,66 +185,10 @@ Custom converter functions can be defined with the `converter` pragma
|
||||
|
||||
## Built-in functions
|
||||
|
||||
The standard library provides these built-in functions:
|
||||
The standard library provides built-in functions for output (`print`, `panic`),
|
||||
ownership (`borrow`, `clone`, `move`, `destroy`), type introspection (`sizeof`,
|
||||
`typeof`, `needsDestroy`), collection queries (`len`, `low`, `high`), heap allocation
|
||||
(`new`), raw memory (`alloc`, `create`, `realloc`, `dealloc`, `copyMem`, `cast`),
|
||||
and iterator operations (`start`, `resume`, `next`).
|
||||
|
||||
| Function | Description |
|
||||
|----------|-------------|
|
||||
| `print(x)` | Print a value to stdout followed by a newline |
|
||||
| `panic()` | Abort the program with a runtime panic |
|
||||
| `panic(msg)` | Abort with a message |
|
||||
| `borrow(x)` or `&x` | Create a non-owning borrow (`lent`) of `x` |
|
||||
| `move(src, dst)` | Explicitly move `src` into `dst` |
|
||||
| `clone(x)` | Create an independent copy of `x` |
|
||||
| `cast[T](x)` | Reinterpret `x` as `T` for low-level raw-pointer or same-size scalar bitcasts. Requires `unsafe`. |
|
||||
| `new(T)` | Heap-allocate a new value of type `T` |
|
||||
| `low(T)` | Return the minimum value of a numeric type (`-inf` for floats) |
|
||||
| `high(T)` | Return the maximum value of a numeric type (`inf` for floats) |
|
||||
| `typeof(x)` | Return the compile-time type witness for the value `x` |
|
||||
| `sizeof(T)` | Return the compile-time size in bytes of a sized type |
|
||||
| `sizeof(x)` | Return the compile-time size in bytes of the type of `x` |
|
||||
| `needsDestroy(T)` | Return whether values of type `T` carry owned cleanup work |
|
||||
| `low(x)` | Return the first valid index of a string, array, or `seq` |
|
||||
| `high(x)` | Return the last valid index of a string, array, or `seq` |
|
||||
| `len(x)` | Return the length of a collection |
|
||||
| `alloc(T, n)` | Allocate raw storage for `n` values of type `T` (uninitialized). Requires `unsafe`. |
|
||||
| `create(T, n)` | Allocate zero-initialized raw storage for `n` values of type `T`. Requires `unsafe`. |
|
||||
| `realloc(ptr, n)` | Resize a raw allocation to `n` elements. Requires `unsafe`. |
|
||||
| `dealloc(ptr)` | Free a raw pointer allocation. Requires `unsafe`. |
|
||||
| `copyMem(dst, src, n)` | Copy `n` bytes from `src` to `dst` (well-defined even for overlapping regions). Requires `unsafe`. |
|
||||
| `addr(x)` | Take the raw address of a raw-pointer-backed value, returning `ptr T`. |
|
||||
| `append(s, x)` | Append element `x` to `mut lent seq[T]` |
|
||||
| `start(g)` | Start a generator, returning `GeneratorState[Y, R]` |
|
||||
| `resume(g, v)` | Resume a generator with send value `v`, returning `GeneratorState[Y, R]` |
|
||||
| `next(it)` | Advance an iterator or generator, returning `Option[Y]` |
|
||||
|
||||
For collections, valid indices are `low(x) .. high(x)` when the collection is not
|
||||
empty. For strings, arrays, and `seq`s, `low(x)` is always `0` and `high(x)` is the
|
||||
last valid index (`-1` for empty values).
|
||||
|
||||
`typeof(x)` returns a compile-time type witness, which can be passed to helpers like
|
||||
`sizeof`. Both `sizeof(T)` and `sizeof(x)` are compile-time constants. They are useful
|
||||
for raw allocation helpers and FFI-style layout checks:
|
||||
|
||||
```peon
|
||||
type Pair = object {
|
||||
left: int64;
|
||||
right: int64;
|
||||
}
|
||||
|
||||
print(sizeof(int64)); # 8
|
||||
print(sizeof(array[3, int64])); # 24
|
||||
print(sizeof(Pair)); # 16
|
||||
let pair = Pair(left = 1, right = 2);
|
||||
print(sizeof(pair)); # 16
|
||||
```
|
||||
|
||||
String indexing uses the same bounds as `low(text)` and `high(text)`, but because
|
||||
strings are immutable it returns an owned `char` value rather than a borrow:
|
||||
|
||||
```peon
|
||||
let text = "abc";
|
||||
let middle: char = text[1];
|
||||
print(middle); # b
|
||||
print(low(text)); # 0
|
||||
print(high(text)); # 2
|
||||
```
|
||||
See [Standard Library -- Built-in Functions](stdlib/builtins.md) for the full reference.
|
||||
|
||||
@@ -14,9 +14,12 @@ async fn parallelSum(a: string, b: string): int64 {
|
||||
}
|
||||
```
|
||||
|
||||
For the async runtime API (`runAsync`, `AsyncCompletion`, timing/cancellation helpers),
|
||||
see [Standard Library -- Async Runtime](stdlib/async.md).
|
||||
|
||||
Current status:
|
||||
|
||||
- synchronous code enters async execution with `runAsync(...)`, which returns `AsyncCompletion[T]`
|
||||
- synchronous code enters async execution with [`runAsync(...)`](stdlib/async.md#runasync), which returns [`AsyncCompletion[T]`](stdlib/types.md#asynccompletiont)
|
||||
- `async fn` bodies may use `await`, and async roots run through the native C backend
|
||||
- `spawn` starts child work inside a `nursery`, and `await` accepts either direct async calls or `SpawnHandle[Return]`
|
||||
- async calls must be explicitly `await`ed or `spawn`ed
|
||||
|
||||
@@ -10,8 +10,10 @@ in), Rust, C and many others.
|
||||
|
||||
## Table of contents
|
||||
|
||||
### Language
|
||||
|
||||
- [Basics](basics.md) -- variables, comments, strings, primitive types
|
||||
- [Type Declarations](types.md) -- objects, tuples, ref objects, enums, standard library types
|
||||
- [Type Declarations](types.md) -- objects, tuples, ref objects, enums
|
||||
- [Functions](functions.md) -- functions, async, lambdas, closures, UFCS
|
||||
- [Control Flow](control-flow.md) -- if/else, while, for, pattern matching, blocks
|
||||
- [Generics](generics.md) -- parametric polymorphism, constraints, static parameters
|
||||
@@ -23,6 +25,24 @@ in), Rust, C and many others.
|
||||
- [Compile-Time Features](compile-time.md) -- `when`/`defined()`, CTFE, pragmas
|
||||
- [Modules](modules.md) -- import/export, visibility, module execution
|
||||
- [C Interop](c-interop.md) -- importc, exportc, C-compatible types, converters
|
||||
|
||||
### Standard Library
|
||||
|
||||
- **[Standard Library Reference](stdlib/index.md)** -- full API documentation
|
||||
- [Built-in Functions](stdlib/builtins.md) -- print, panic, borrow, clone, sizeof, etc.
|
||||
- [Option and Result](stdlib/types.md) -- Option[T], Result[T, E], AsyncCompletion[T]
|
||||
- [Collections](stdlib/collections.md) -- array[N, T], seq[T], deque[T]
|
||||
- [Iterators](stdlib/iterators.md) -- Generator, Iterator, Iterable protocols
|
||||
- [Math](stdlib/math.md) -- constants and functions
|
||||
- [Strings](stdlib/strings.md) -- concat, join, operators
|
||||
- [Ranges](stdlib/ranges.md) -- InclusiveRange, ExclusiveRange, .., ..<
|
||||
- [Async Runtime](stdlib/async.md) -- runAsync, sleep, cancellation, WaitQueue
|
||||
- [Networking](stdlib/net.md) -- sockets, getAddrInfo, readSome/writeSome
|
||||
- [Time](stdlib/time.md) -- cpuTime
|
||||
- [Synchronization](stdlib/sync.md) -- Event, LIFOQueue, FIFOQueue
|
||||
|
||||
### Reference
|
||||
|
||||
- [Grammar](../grammar.md)
|
||||
- [Bytecode](../bytecode.md)
|
||||
|
||||
|
||||
@@ -117,3 +117,7 @@ corresponding iterator type via `iter()`, `items()`, and `mitems()`.
|
||||
Types can participate in `for` loops by implementing the direct iterator
|
||||
protocol (`Iterator[T]`), or by implementing one of the collection adapter
|
||||
protocols.
|
||||
|
||||
For `Generator[Y, S, R]`, `GeneratorState`, and the `start`/`resume`/`next`
|
||||
advancement functions, see the
|
||||
[Standard Library -- Iterators](stdlib/iterators.md) reference.
|
||||
|
||||
95
docs/manual/stdlib/async.md
Normal file
95
docs/manual/stdlib/async.md
Normal file
@@ -0,0 +1,95 @@
|
||||
# Async Runtime
|
||||
|
||||
[Back to Standard Library](index.md) | [Back to Manual](../index.md)
|
||||
|
||||
The async runtime provides the execution infrastructure for
|
||||
[structured concurrency](../concurrency.md). Available through the implicit `import std`.
|
||||
|
||||
## Entry point
|
||||
|
||||
### `runAsync`
|
||||
|
||||
The sync-to-async bridge. Returns [`AsyncCompletion[T]`](types.md#asynccompletiont):
|
||||
|
||||
```peon
|
||||
fn runAsync[T](value: T): AsyncCompletion[T]
|
||||
fn runAsync[T](value: T, options: AsyncRuntimeOptions): AsyncCompletion[T]
|
||||
```
|
||||
|
||||
`runAsync` is rejected inside `async fn` -- it is only for entering the async
|
||||
world from synchronous code.
|
||||
|
||||
### `AsyncRuntimeOptions`
|
||||
|
||||
```peon
|
||||
type AsyncRuntimeOptions = object with ImplicitCopy {
|
||||
maxBlockingThreads: int64;
|
||||
maxBlockingJobs: int64;
|
||||
}
|
||||
```
|
||||
|
||||
| Field | Description |
|
||||
|-------|-------------|
|
||||
| `maxBlockingThreads` | Maximum idle threads in the blocking call pool. |
|
||||
| `maxBlockingJobs` | Maximum blocking jobs queued at once. |
|
||||
|
||||
## Clock
|
||||
|
||||
| Function | Description |
|
||||
|----------|-------------|
|
||||
| `clock()` | Return an `AsyncClock` for measuring async time. |
|
||||
| `now(clock)` | Return the current time as `float` from an `AsyncClock`. |
|
||||
|
||||
## Timing and sleep
|
||||
|
||||
All timing functions are `async fn` and require an async context.
|
||||
|
||||
| Function | Description |
|
||||
|----------|-------------|
|
||||
| `sleep(seconds)` | Suspend the current task for `seconds`. |
|
||||
| `sleepUntil(deadline)` | Suspend until the absolute `deadline`. |
|
||||
| `checkpoint()` | Yield control to the scheduler. Every `await` should be a checkpoint. |
|
||||
|
||||
## Cancellation
|
||||
|
||||
These operate on [`nursery`](../concurrency.md#current-rules) capabilities:
|
||||
|
||||
| Function | Description |
|
||||
|----------|-------------|
|
||||
| `cancel(nursery)` | Cancel a nursery immediately. |
|
||||
| `cancelAfter(nursery, seconds)` | Cancel the nursery after `seconds`. |
|
||||
| `cancelAt(nursery, deadline)` | Cancel the nursery at an absolute `deadline`. |
|
||||
| `clearDeadline(nursery)` | Remove the cancellation deadline. |
|
||||
| `deadline(nursery)` | Return the current deadline as `Option[float]`. |
|
||||
| `extendDeadline(nursery, seconds)` | Extend the deadline by `seconds`. |
|
||||
|
||||
## I/O waiting
|
||||
|
||||
| Function | Description |
|
||||
|----------|-------------|
|
||||
| `waitReadable(fd)` | `async fn` -- suspend until file descriptor `fd` is readable. |
|
||||
| `waitWritable(fd)` | `async fn` -- suspend until file descriptor `fd` is writable. |
|
||||
|
||||
These are the building blocks for non-blocking I/O in the [networking](net.md) module.
|
||||
|
||||
## `WaitQueue`
|
||||
|
||||
A low-level task parking primitive used by [synchronization types](sync.md):
|
||||
|
||||
```peon
|
||||
type WaitQueue = object { ... }
|
||||
```
|
||||
|
||||
| Function | Description |
|
||||
|----------|-------------|
|
||||
| `WaitQueue()` | Construct an empty wait queue. |
|
||||
| `init(q)` | Re-initialize a wait queue. |
|
||||
| `wakeFirst(q)` | Wake the first parked task. Returns `true` if a task was woken. |
|
||||
| `wakeLast(q)` | Wake the last parked task. Returns `true` if a task was woken. |
|
||||
| `wakeAll(q)` | Wake all parked tasks. Returns the count woken. |
|
||||
| `isEmpty(q)` | Return whether no tasks are parked. |
|
||||
| `park(q)` | `async fn` -- suspend the current task in the queue. |
|
||||
|
||||
`WaitQueue` is imported from the C runtime and is not intended for direct use
|
||||
in application code. Use [`Event`](sync.md#event) or the async
|
||||
[queues](sync.md#async-queues) instead.
|
||||
113
docs/manual/stdlib/builtins.md
Normal file
113
docs/manual/stdlib/builtins.md
Normal file
@@ -0,0 +1,113 @@
|
||||
# Built-in Functions
|
||||
|
||||
[Back to Standard Library](index.md) | [Back to Manual](../index.md)
|
||||
|
||||
These functions are available in every module through the implicit `import std`.
|
||||
|
||||
## Output and diagnostics
|
||||
|
||||
| Function | Description |
|
||||
|----------|-------------|
|
||||
| `print(x)` | Print a value to stdout followed by a newline. Accepts any [`Printable`](../interfaces.md#built-in-interfaces) type. |
|
||||
| `panic()` | Abort the program with a runtime panic. |
|
||||
| `panic(msg)` | Abort with a message. |
|
||||
|
||||
## Ownership and copying
|
||||
|
||||
| Function | Description |
|
||||
|----------|-------------|
|
||||
| `borrow(x)` or `&x` | Create a non-owning borrow (`lent T`) of `x`. See [Memory Model -- Borrows](../memory-model.md#borrows-and-lent). |
|
||||
| `clone(x)` | Create an independent copy of `x`. Requires `T: Copy`. See [Interfaces -- Copy](../interfaces.md#built-in-interfaces). |
|
||||
| `move(src, dst)` | Explicitly move `src` into `dst`. |
|
||||
| `destroy(x)` | Explicitly destroy a value. See [Memory Model -- Lifecycle hooks](../memory-model.md#lifecycle-hooks). |
|
||||
| `defaultClone()` | Default clone implementation (only valid inside a `clone=` hook). |
|
||||
| `defaultMove()` | Default move implementation (only valid inside a `move=` hook). |
|
||||
| `defaultDestroy()` | Default destroy implementation (only valid inside a `destroy=` hook). |
|
||||
|
||||
## Type introspection
|
||||
|
||||
| Function | Description |
|
||||
|----------|-------------|
|
||||
| `typeof(x)` | Return the compile-time type witness for the value `x`. |
|
||||
| `sizeof(T)` | Return the compile-time size in bytes of a sized type. |
|
||||
| `sizeof(x)` | Return the compile-time size in bytes of the type of `x`. |
|
||||
| `needsDestroy(T)` | Return whether values of type `T` carry owned cleanup work. Used in generic [lifecycle hooks](../memory-model.md#lifecycle-hooks). |
|
||||
|
||||
Both `sizeof(T)` and `sizeof(x)` are compile-time constants:
|
||||
|
||||
```peon
|
||||
type Pair = object {
|
||||
left: int64;
|
||||
right: int64;
|
||||
}
|
||||
|
||||
print(sizeof(int64)); # 8
|
||||
print(sizeof(array[3, int64])); # 24
|
||||
print(sizeof(Pair)); # 16
|
||||
let pair = Pair(left = 1, right = 2);
|
||||
print(sizeof(pair)); # 16
|
||||
```
|
||||
|
||||
## Collection queries
|
||||
|
||||
| Function | Description |
|
||||
|----------|-------------|
|
||||
| `len(x)` | Return the length of a string, [array](collections.md#static-arrays), [seq](collections.md#sequences), or [deque](collections.md#double-ended-queue). |
|
||||
| `low(T)` | Return the minimum value of a numeric type (`-inf` for floats). |
|
||||
| `high(T)` | Return the maximum value of a numeric type (`inf` for floats). |
|
||||
| `low(x)` | Return the first valid index of a string, array, or `seq` (always `0`). |
|
||||
| `high(x)` | Return the last valid index of a string, array, or `seq` (`-1` for empty values). |
|
||||
|
||||
For strings, arrays, and `seq`s, valid indices are `low(x)` through `high(x)`.
|
||||
|
||||
String indexing returns an owned `char` value (strings are immutable):
|
||||
|
||||
```peon
|
||||
let text = "abc";
|
||||
let middle: char = text[1];
|
||||
print(middle); # b
|
||||
print(low(text)); # 0
|
||||
print(high(text)); # 2
|
||||
```
|
||||
|
||||
## Heap allocation
|
||||
|
||||
| Function | Description |
|
||||
|----------|-------------|
|
||||
| `new(T)` | Heap-allocate a new value of type `T`, returning `ref T`. |
|
||||
|
||||
```peon
|
||||
var cell = new(int64);
|
||||
cell[] = 42;
|
||||
print(cell[]); # 42
|
||||
```
|
||||
|
||||
## Raw memory (unsafe)
|
||||
|
||||
These require [`unsafe { ... }`](../unsafe.md#unsafe-blocks):
|
||||
|
||||
| Function | Description |
|
||||
|----------|-------------|
|
||||
| `alloc(T, n)` | Allocate raw storage for `n` values of type `T` (uninitialized). Returns `ptr T`. |
|
||||
| `create(T, n)` | Allocate zero-initialized raw storage for `n` values of type `T`. Returns `ptr T`. |
|
||||
| `realloc(ptr, n)` | Resize a raw allocation to `n` elements. Returns `ptr T`. |
|
||||
| `dealloc(ptr)` | Free a raw pointer allocation. |
|
||||
| `copyMem(dst, src, n)` | Copy `n` bytes from `src` to `dst` (well-defined for overlapping regions). |
|
||||
| `addr(x)` | Take the raw address of a raw-pointer-backed value, returning `ptr T`. |
|
||||
| `cast[T](x)` | Reinterpret the bits of `x` as type `T`. Source and target must have the same size. |
|
||||
|
||||
See [Unsafe -- Raw pointers](../unsafe.md#raw-pointers) for usage examples.
|
||||
|
||||
## Sequence operations
|
||||
|
||||
| Function | Description |
|
||||
|----------|-------------|
|
||||
| `append(s, x)` | Append element `x` to `mut lent seq[T]`. See [Collections -- Sequences](collections.md#sequences). |
|
||||
|
||||
## Generator and iterator operations
|
||||
|
||||
| Function | Description |
|
||||
|----------|-------------|
|
||||
| `start(g)` | Start a [generator](iterators.md#generators), returning `GeneratorState[Y, R]`. |
|
||||
| `resume(g, v)` | Resume a generator with send value `v`, returning `GeneratorState[Y, R]`. |
|
||||
| `next(it)` | Advance an [iterator](iterators.md#iterator-interfaces) or generator, returning `Option[Y]`. |
|
||||
172
docs/manual/stdlib/collections.md
Normal file
172
docs/manual/stdlib/collections.md
Normal file
@@ -0,0 +1,172 @@
|
||||
# Collections
|
||||
|
||||
[Back to Standard Library](index.md) | [Back to Manual](../index.md)
|
||||
|
||||
## Static arrays (`array[N, T]`)
|
||||
|
||||
The built-in `array[N, T]` type constructor creates fixed-size arrays:
|
||||
|
||||
```peon
|
||||
type IntVec = array[3, int64];
|
||||
|
||||
var a = IntVec(1, 2, 3);
|
||||
var b = [1, 2, 3, 4]; # Inferred as array[4, int64]
|
||||
|
||||
print(a[0]); # 1
|
||||
a[0] = 9;
|
||||
print(len(a)); # 3
|
||||
```
|
||||
|
||||
Array access is bounds-checked at runtime when `boundChecks` is enabled
|
||||
(see [Compile-Time Features -- Config symbols](../compile-time.md#config-symbols)).
|
||||
Out-of-bounds access panics.
|
||||
|
||||
### Value semantics
|
||||
|
||||
Plain arrays are value types. Assignment moves the array:
|
||||
|
||||
```peon
|
||||
var a = [1, 2, 3];
|
||||
var b = a; # a is moved into b
|
||||
# print(a[0]); # Error: a has been moved
|
||||
print(b[0]); # 1
|
||||
```
|
||||
|
||||
Use `clone` for an independent copy:
|
||||
|
||||
```peon
|
||||
var a = [1, 2, 3];
|
||||
var b = clone(a);
|
||||
b[0] = 9;
|
||||
print(a[0]); # 1 -- unchanged
|
||||
```
|
||||
|
||||
### Ref arrays
|
||||
|
||||
Heap-allocated arrays can be mutably borrowed:
|
||||
|
||||
```peon
|
||||
type RefVec = ref array[2, int64];
|
||||
|
||||
var a = RefVec(4, 5);
|
||||
var b = mut borrow(a);
|
||||
b[1] = 7;
|
||||
print(a[1]); # 7 -- shared data
|
||||
```
|
||||
|
||||
### API
|
||||
|
||||
| Function | Description |
|
||||
|----------|-------------|
|
||||
| `len(a)` | Return the array length (compile-time constant `N`). |
|
||||
| `low(a)` | Return `0`. |
|
||||
| `high(a)` | Return `N - 1`. |
|
||||
| `items(a)` | Generator yielding `lent T` for each element. |
|
||||
| `mitems(a)` | Generator yielding `mut lent T` for each element. |
|
||||
| `indexOf(a, v)` | Return `Option[int64]` with the index of the first match. |
|
||||
| `unsafe { get_unchecked(a, i) }` | Element access without bounds checking. |
|
||||
|
||||
## Sequences (`seq[T]`)
|
||||
|
||||
`seq[T]` is a growable dynamic array. Create one with the `@` prefix on an array
|
||||
literal:
|
||||
|
||||
```peon
|
||||
var ints = @[1, 2, 3];
|
||||
ints.append(4);
|
||||
print(len(ints)); # 4
|
||||
print(ints[3][]); # 4
|
||||
```
|
||||
|
||||
The `@` operator also converts a static array to a `seq`:
|
||||
|
||||
```peon
|
||||
var arr = [1, 2, 3];
|
||||
var s = @arr; # seq[int64]
|
||||
```
|
||||
|
||||
### Indexing semantics
|
||||
|
||||
- `s[i]` returns a **borrow** (`lent T` or `mut lent T`), not an owned value.
|
||||
- For scalars, use `s[i][]` (whole-deref) to get the owned value.
|
||||
- `s[i] = newValue` assigns through a mutable borrow.
|
||||
- Field access works through borrows: `boxes[0].value` is valid.
|
||||
|
||||
```peon
|
||||
type Box = object { value: int64; }
|
||||
|
||||
var boxes = @[Box(value = 1), Box(value = 2)];
|
||||
let first: mut lent Box = boxes[0];
|
||||
first.value = 9;
|
||||
|
||||
var ints = @[1, 2, 3];
|
||||
ints[1] = 7;
|
||||
print(ints[1][]); # 7
|
||||
```
|
||||
|
||||
### API
|
||||
|
||||
| Function | Description |
|
||||
|----------|-------------|
|
||||
| `newSeq[T]()` | Create an empty sequence. |
|
||||
| `newSeqOfCap[T](n)` | Create an empty sequence with pre-allocated capacity. |
|
||||
| `append(s, x)` | Append element `x` to the end. |
|
||||
| `pop(s, i)` | Remove element at index `i`, shift tail left, return the removed value. |
|
||||
| `pop(s)` | Remove and return the last element. Panics if empty. |
|
||||
| `delete(s, i)` | Remove element at index `i` and discard it. |
|
||||
| `len(s)` | Return the current length. |
|
||||
| `low(s)` | Return `0`. |
|
||||
| `high(s)` | Return `len - 1`. |
|
||||
| `indexOf(s, v)` | Return `Option[int64]` with the index of the first match. |
|
||||
| `items(s)` | Generator yielding `lent T` for each element. |
|
||||
| `mitems(s)` | Generator yielding `mut lent T` for each element. |
|
||||
| `toString(s)` | Convert to string representation (requires `T: Printable`). |
|
||||
| `unsafe { get_unchecked(s, i) }` | Element access without bounds checking. |
|
||||
|
||||
### Implementation note
|
||||
|
||||
`seq[T]` stores its payload through an internal `Buffer[T]` owner cell. Element
|
||||
borrows and [iterator](iterators.md) yields are anchored to the buffer storage
|
||||
owner rather than the seq header. If growth moves the raw payload, the buffer
|
||||
swaps to a new owner so old element borrows go stale cleanly instead of silently
|
||||
dangling into moved memory.
|
||||
|
||||
`seq[T]` is a runtime collection. [Compile-time evaluation](../compile-time.md#ctfe-limitations)
|
||||
rejects it because CTFE does not permit heap-backed sequence storage.
|
||||
|
||||
## Double-ended queue (`deque[T]`)
|
||||
|
||||
`deque[T]` is a ring-buffer-backed double-ended queue with O(1) amortized push/pop
|
||||
at both ends and O(1) random access by index:
|
||||
|
||||
```peon
|
||||
var d = newDeque[int64]();
|
||||
d.pushBack(1);
|
||||
d.pushBack(2);
|
||||
d.pushFront(0);
|
||||
print(d[0][]); # 0
|
||||
print(d.popFront()); # 0
|
||||
print(d.popBack()); # 2
|
||||
```
|
||||
|
||||
### API
|
||||
|
||||
| Function | Description |
|
||||
|----------|-------------|
|
||||
| `newDeque[T](capacity = 4)` | Create a new deque with optional initial capacity. |
|
||||
| `pushBack(d, v)` | Add element to the back. |
|
||||
| `pushFront(d, v)` | Add element to the front. |
|
||||
| `popFront(d)` | Remove and return the front element. Panics if empty. |
|
||||
| `popBack(d)` | Remove and return the back element. Panics if empty. |
|
||||
| `peekFront(d)` | View the front element without removing (`lent T` or `mut lent T`). |
|
||||
| `peekBack(d)` | View the back element without removing (`lent T` or `mut lent T`). |
|
||||
| `len(d)` | Return the current length. |
|
||||
| `high(d)` | Return `len - 1`. |
|
||||
| `isEmpty(d)` | Return whether the deque is empty. |
|
||||
| `items(d)` | Generator yielding `lent T` for each element. |
|
||||
| `mitems(d)` | Generator yielding `mut lent T` for each element. |
|
||||
| `toString(d)` | Convert to string representation (requires `T: Printable`). |
|
||||
| `unsafe { get_unchecked(d, i) }` | Element access without bounds checking. |
|
||||
|
||||
Indexing with `d[i]` and `d[i] = v` is also supported, with the same borrow
|
||||
semantics as `seq[T]`.
|
||||
21
docs/manual/stdlib/index.md
Normal file
21
docs/manual/stdlib/index.md
Normal file
@@ -0,0 +1,21 @@
|
||||
# Standard Library Reference
|
||||
|
||||
[Back to Manual](../index.md)
|
||||
|
||||
All programs implicitly `import std`, which re-exports the entire standard library.
|
||||
Individual modules can also be imported directly (e.g. `import net`, `import cinterop`).
|
||||
|
||||
## Modules
|
||||
|
||||
- [Built-in Functions](builtins.md) -- `print`, `panic`, `borrow`, `clone`, `new`, `sizeof`, allocation, etc.
|
||||
- [Types](types.md) -- `Option[T]`, `Result[T, E]`, primitive type details
|
||||
- [Collections](collections.md) -- `array[N, T]`, `seq[T]`, `deque[T]`
|
||||
- [Iterators](iterators.md) -- `Generator`, `GeneratorState`, `Iterator`, `Iterable` protocols
|
||||
- [Math](math.md) -- constants (`pi`, `tau`, `e`) and functions (`sqrt`, `sin`, `cos`, etc.)
|
||||
- [Strings](strings.md) -- `concat`, `join`, `+`, `+=`
|
||||
- [Ranges](ranges.md) -- `InclusiveRange`, `ExclusiveRange`, `..`, `..<`
|
||||
- [Async Runtime](async.md) -- `runAsync`, `AsyncCompletion`, timing/cancellation helpers, `WaitQueue`
|
||||
- [Networking](net.md) -- sockets, `getAddrInfo`, `readSome`/`writeSome`
|
||||
- [Time](time.md) -- `cpuTime`
|
||||
- [Synchronization](sync.md) -- `Event`, `LIFOQueue`, `FIFOQueue`
|
||||
- [C Interop Types](../c-interop.md) -- `cint`, `cstring`, `csize`, etc. (documented in the language manual)
|
||||
96
docs/manual/stdlib/iterators.md
Normal file
96
docs/manual/stdlib/iterators.md
Normal file
@@ -0,0 +1,96 @@
|
||||
# Iterators and Generators
|
||||
|
||||
[Back to Standard Library](index.md) | [Back to Manual](../index.md)
|
||||
|
||||
## Iterator interfaces
|
||||
|
||||
The standard library defines a hierarchy of iterator and iterable
|
||||
[interfaces](../interfaces.md) used by [`for` loops](../control-flow.md#for-loops):
|
||||
|
||||
```peon
|
||||
iface Iterator[T] {
|
||||
fn next(mut self): Option[T];
|
||||
}
|
||||
|
||||
iface BorrowIterator[lent T] from Iterator[T] {
|
||||
# Yields borrowed elements
|
||||
}
|
||||
|
||||
iface MutBorrowIterator[mut lent T] from Iterator[T] {
|
||||
# Yields mutable borrowed elements
|
||||
}
|
||||
```
|
||||
|
||||
`Iterator` is the base cursor protocol. `BorrowIterator` and
|
||||
`MutBorrowIterator` are subtypes for iterators that yield borrowed or
|
||||
mutable-borrowed elements.
|
||||
|
||||
Collection-side adapters produce iterators:
|
||||
|
||||
```peon
|
||||
iface Iterable[T] {
|
||||
fn iter(lent self): Iterator[T];
|
||||
}
|
||||
|
||||
iface BorrowIterable[lent T] {
|
||||
fn items(lent self): BorrowIterator[lent T];
|
||||
}
|
||||
|
||||
iface MutBorrowIterable[mut lent T] {
|
||||
fn mitems(mut self): MutBorrowIterator[mut lent T];
|
||||
}
|
||||
```
|
||||
|
||||
Types can participate in `for` loops by implementing the direct iterator
|
||||
protocol (`Iterator[T]`) or one of the collection adapter protocols.
|
||||
|
||||
## Generators
|
||||
|
||||
`Generator[Yield, Send, Return]` is the built-in generator type. It implements
|
||||
`Iterator[Yield]`. Generators are declared with the `generator` keyword
|
||||
(see [Concurrency -- Generators](../concurrency.md#generators)):
|
||||
|
||||
```peon
|
||||
generator fn range(start: int64, stop: int64): Generator[int64, void, void] {
|
||||
var i = start;
|
||||
while i < stop {
|
||||
yield i;
|
||||
i = i + 1;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
- `Yield` -- the type produced by `yield`.
|
||||
- `Send` -- the type callers send back on each resumption (`void` if none).
|
||||
- `Return` -- the final return type when the generator completes (`void` for
|
||||
generators that simply exhaust).
|
||||
|
||||
## `GeneratorState[Yield, Return]`
|
||||
|
||||
The low-level result of advancing a generator:
|
||||
|
||||
```peon
|
||||
type GeneratorState[Yield, Return] = enum {
|
||||
Yielded { value: Yield; },
|
||||
Complete { value: Return; }
|
||||
}
|
||||
```
|
||||
|
||||
## Advancement functions
|
||||
|
||||
| Function | Description |
|
||||
|----------|-------------|
|
||||
| `start(g)` | Start a generator, returning `GeneratorState[Y, R]`. |
|
||||
| `resume(g, v)` | Resume a generator with send value `v`, returning `GeneratorState[Y, R]`. |
|
||||
| `next(it)` | Advance any iterator or generator, returning `Option[Y]`. Wraps start/resume for the common case. |
|
||||
|
||||
```peon
|
||||
var g = range(0, 3);
|
||||
match next(g) {
|
||||
case Some(v) { print(v); } # 0
|
||||
case None { }
|
||||
}
|
||||
```
|
||||
|
||||
For generator delegation with `yield from`, borrow safety rules, and
|
||||
`#pragma[lentFrom]`, see [Concurrency -- Generators](../concurrency.md#generators).
|
||||
47
docs/manual/stdlib/math.md
Normal file
47
docs/manual/stdlib/math.md
Normal file
@@ -0,0 +1,47 @@
|
||||
# Math
|
||||
|
||||
[Back to Standard Library](index.md) | [Back to Manual](../index.md)
|
||||
|
||||
Mathematical constants and functions. Available through the implicit `import std`.
|
||||
|
||||
## Constants
|
||||
|
||||
| Name | Value | Description |
|
||||
|------|-------|-------------|
|
||||
| `pi` | 3.141592653589793 | Ratio of circumference to diameter |
|
||||
| `tau` | 6.283185307179586 | 2 * pi |
|
||||
| `e` | 2.718281828459045 | Euler's number |
|
||||
|
||||
## Functions
|
||||
|
||||
All functions are overloaded for both `float64` and `float32`.
|
||||
|
||||
| Function | Description |
|
||||
|----------|-------------|
|
||||
| `min(a, b)` | Return the smaller of two values. Generic over `Number`. |
|
||||
| `max(a, b)` | Return the larger of two values. Generic over `Number`. |
|
||||
| `clamp(value, low, high)` | Clamp `value` to the range `[low, high]`. Generic over `Number`. |
|
||||
| `sqrt(x)` | Square root. |
|
||||
| `exp(x)` | Exponential function (e^x). |
|
||||
| `ln(x)` | Natural logarithm. |
|
||||
| `log(x, base)` | Logarithm with arbitrary base. Computed as `ln(x) / ln(base)`. |
|
||||
| `sin(x)` | Sine. |
|
||||
| `cos(x)` | Cosine. |
|
||||
| `tan(x)` | Tangent. Computed as `sin(x) / cos(x)`. |
|
||||
| `atan2(y, x)` | Two-argument arctangent. |
|
||||
|
||||
## Arithmetic operators
|
||||
|
||||
The standard library also provides built-in arithmetic operators for all numeric
|
||||
types, including wrapping variants:
|
||||
|
||||
| Function | Description |
|
||||
|----------|-------------|
|
||||
| `wrapping_add(a, b)` | Addition with overflow wrap. |
|
||||
| `wrapping_sub(a, b)` | Subtraction with overflow wrap. |
|
||||
| `wrapping_mul(a, b)` | Multiplication with overflow wrap. |
|
||||
| `wrapping_neg(a)` | Negation with overflow wrap. |
|
||||
| `wrapping_div(a, b)` | Division with overflow wrap. |
|
||||
| `wrapping_rem(a, b)` | Remainder with overflow wrap. |
|
||||
|
||||
The `**` power operator is defined for integer types.
|
||||
132
docs/manual/stdlib/net.md
Normal file
132
docs/manual/stdlib/net.md
Normal file
@@ -0,0 +1,132 @@
|
||||
# Networking
|
||||
|
||||
[Back to Standard Library](index.md) | [Back to Manual](../index.md)
|
||||
|
||||
The `net` module provides async socket I/O on top of the
|
||||
[async runtime](async.md). Import it explicitly:
|
||||
|
||||
```peon
|
||||
import net;
|
||||
```
|
||||
|
||||
## Types
|
||||
|
||||
### `Fd`
|
||||
|
||||
A file descriptor, aliased to `int32`.
|
||||
|
||||
### `SocketFamily`
|
||||
|
||||
```peon
|
||||
type SocketFamily = enum {
|
||||
AnyFamily = 0,
|
||||
Unix,
|
||||
Inet,
|
||||
Inet6
|
||||
}
|
||||
```
|
||||
|
||||
### `SocketKind`
|
||||
|
||||
```peon
|
||||
type SocketKind = enum {
|
||||
AnyKind = 0,
|
||||
Stream,
|
||||
Datagram
|
||||
}
|
||||
```
|
||||
|
||||
### `IOError`
|
||||
|
||||
```peon
|
||||
type IOError = object with Printable, ImplicitCopy {
|
||||
code: int32;
|
||||
}
|
||||
```
|
||||
|
||||
| Method | Description |
|
||||
|--------|-------------|
|
||||
| `errorCode(e)` | Return the raw error code. |
|
||||
| `wouldBlock(e)` | Check if `EWOULDBLOCK`/`EAGAIN`. |
|
||||
| `interrupted(e)` | Check if `EINTR`. |
|
||||
| `inProgress(e)` | Check if `EINPROGRESS`. |
|
||||
| `toString(e)` | String representation. |
|
||||
|
||||
### `SocketPair`
|
||||
|
||||
```peon
|
||||
type SocketPair = object with ImplicitCopy {
|
||||
left: Fd;
|
||||
right: Fd;
|
||||
}
|
||||
```
|
||||
|
||||
| Method | Description |
|
||||
|--------|-------------|
|
||||
| `left(p)` | Return the left file descriptor. |
|
||||
| `right(p)` | Return the right file descriptor. |
|
||||
|
||||
### `SocketAddress`
|
||||
|
||||
A resolved network address with `family`, `kind`, `protocol`, `addressLen`, and
|
||||
opaque `storage`.
|
||||
|
||||
| Method | Description |
|
||||
|--------|-------------|
|
||||
| `family(a)` | Return the `SocketFamily`. |
|
||||
| `kind(a)` | Return the `SocketKind`. |
|
||||
| `protocol(a)` | Return the protocol number. |
|
||||
| `addressLen(a)` | Return the address length. |
|
||||
|
||||
### `AddressInfoError`
|
||||
|
||||
| Method | Description |
|
||||
|--------|-------------|
|
||||
| `code(e)` | Return the GAI error code. |
|
||||
| `toString(e)` | Human-readable error string. |
|
||||
|
||||
## Socket operations
|
||||
|
||||
| Function | Description |
|
||||
|----------|-------------|
|
||||
| `socket(family, kind, protocol)` | Create a non-blocking socket. Returns `Result[Fd, IOError]`. |
|
||||
| `socketPair(family, kind, protocol)` | Create a connected socket pair. Returns `Result[SocketPair, IOError]`. |
|
||||
| `close(fd)` | Close a file descriptor. Returns `Result[int32, IOError]`. |
|
||||
| `setNonBlocking(fd)` | Set a file descriptor to non-blocking mode. |
|
||||
| `bind(fd, address, addressLen)` | Bind a socket to an address. |
|
||||
| `listen(fd, backlog)` | Mark a socket as listening. |
|
||||
| `socketError(fd)` | Return the pending socket error as `IOError`. |
|
||||
|
||||
## Async I/O
|
||||
|
||||
All of these are `async fn` and must be called from an
|
||||
[async context](../concurrency.md):
|
||||
|
||||
| Function | Description |
|
||||
|----------|-------------|
|
||||
| `connect(fd, address)` | Connect to a `SocketAddress`. Returns `Result[int32, IOError]`. |
|
||||
| `connect(fd, ptr, len)` | Connect to a raw address. |
|
||||
| `accept(fd, ptr, len)` | Accept a connection. Returns `Result[Fd, IOError]`. |
|
||||
| `readSome(fd, buffer, count)` | Read up to `count` bytes. Returns `Result[int64, IOError]`. |
|
||||
| `writeSome(fd, buffer, count)` | Write up to `count` bytes. Returns `Result[int64, IOError]`. |
|
||||
|
||||
All I/O functions handle `EWOULDBLOCK` and `EINTR` internally, using
|
||||
[`waitReadable`/`waitWritable`](async.md#io-waiting) to suspend until the
|
||||
descriptor is ready.
|
||||
|
||||
## Address resolution
|
||||
|
||||
```peon
|
||||
async fn getAddrInfo(host: string, port: int64): Result[seq[SocketAddress], AddressInfoError]
|
||||
async fn getAddrInfo(host: string, port: int64, family: SocketFamily,
|
||||
kind: SocketKind, protocol: int64): Result[seq[SocketAddress], AddressInfoError]
|
||||
```
|
||||
|
||||
Resolve a hostname to a sequence of `SocketAddress` values. The short form
|
||||
defaults to `AnyFamily`, `AnyKind`, protocol `0`.
|
||||
|
||||
```peon
|
||||
import net;
|
||||
|
||||
let addrs = runAsync(getAddrInfo("localhost", 80, Inet, Stream, 0)).unwrap();
|
||||
```
|
||||
46
docs/manual/stdlib/ranges.md
Normal file
46
docs/manual/stdlib/ranges.md
Normal file
@@ -0,0 +1,46 @@
|
||||
# Ranges
|
||||
|
||||
[Back to Standard Library](index.md) | [Back to Manual](../index.md)
|
||||
|
||||
Range types for integer iteration. Available through the implicit `import std`.
|
||||
|
||||
## Types
|
||||
|
||||
```peon
|
||||
type InclusiveRange[T: Integer] = object with Iterable[T] {
|
||||
start: T;
|
||||
stop: T;
|
||||
}
|
||||
|
||||
type ExclusiveRange[T: Integer] = object with Iterable[T] {
|
||||
start: T;
|
||||
stop: T;
|
||||
}
|
||||
|
||||
type range[T] = InclusiveRange[T] | ExclusiveRange[T];
|
||||
```
|
||||
|
||||
Both range types implement [`Iterable[T]`](iterators.md#iterator-interfaces),
|
||||
making them usable in [`for` loops](../control-flow.md#for-loops).
|
||||
|
||||
## Operators
|
||||
|
||||
| Operator | Description |
|
||||
|----------|-------------|
|
||||
| `a .. b` | Create an inclusive range from `a` to `b` (both endpoints included). |
|
||||
| `a ..< b` | Create an exclusive range from `a` to `b` (`b` excluded). |
|
||||
|
||||
## Usage
|
||||
|
||||
```peon
|
||||
for i in 0 ..< 5 {
|
||||
print(i); # 0, 1, 2, 3, 4
|
||||
}
|
||||
|
||||
for i in 1 .. 3 {
|
||||
print(i); # 1, 2, 3
|
||||
}
|
||||
```
|
||||
|
||||
Ranges produce generators via `iter()`, so they integrate with the standard
|
||||
iterator protocol.
|
||||
42
docs/manual/stdlib/strings.md
Normal file
42
docs/manual/stdlib/strings.md
Normal file
@@ -0,0 +1,42 @@
|
||||
# Strings
|
||||
|
||||
[Back to Standard Library](index.md) | [Back to Manual](../index.md)
|
||||
|
||||
String manipulation utilities. Available through the implicit `import std`.
|
||||
|
||||
For string escape sequences and literal syntax, see [Basics -- Strings](../basics.md#strings).
|
||||
|
||||
## Functions
|
||||
|
||||
| Function | Description |
|
||||
|----------|-------------|
|
||||
| `concat(a, b)` | Concatenate two strings. Pure function. |
|
||||
| `join(parts, sep)` | Join a `seq[string]` with a separator string. |
|
||||
| `join(parts)` | Join a `seq[string]` with no separator. |
|
||||
| `join(parts, sep)` | Join a `seq[T: Printable]` with a separator (converts elements via `toString`). |
|
||||
|
||||
## Operators
|
||||
|
||||
| Operator | Description |
|
||||
|----------|-------------|
|
||||
| `a + b` | Concatenate two strings. Equivalent to `concat(a, b)`. |
|
||||
| `a += b` | Append `b` to mutable string `a` in place. |
|
||||
|
||||
```peon
|
||||
let greeting = "hello" + " " + "world";
|
||||
var msg = "hi";
|
||||
msg += "!";
|
||||
print(msg); # hi!
|
||||
```
|
||||
|
||||
## String indexing
|
||||
|
||||
Strings are immutable. Indexing returns an owned `char` value:
|
||||
|
||||
```peon
|
||||
let text = "abc";
|
||||
print(text[1]); # b
|
||||
print(len(text)); # 3
|
||||
print(low(text)); # 0
|
||||
print(high(text)); # 2
|
||||
```
|
||||
86
docs/manual/stdlib/sync.md
Normal file
86
docs/manual/stdlib/sync.md
Normal file
@@ -0,0 +1,86 @@
|
||||
# Synchronization
|
||||
|
||||
[Back to Standard Library](index.md) | [Back to Manual](../index.md)
|
||||
|
||||
Async synchronization primitives for inter-task communication. These are
|
||||
re-exported through `import std`.
|
||||
|
||||
All blocking operations in this module are `async fn` and require an
|
||||
[async context](../concurrency.md).
|
||||
|
||||
## Event
|
||||
|
||||
A simple signal that tasks can wait on:
|
||||
|
||||
```peon
|
||||
var evt = Event();
|
||||
|
||||
# In one task:
|
||||
await evt.wait();
|
||||
|
||||
# In another task:
|
||||
evt.set();
|
||||
```
|
||||
|
||||
| Function | Description |
|
||||
|----------|-------------|
|
||||
| `Event()` | Construct a new unsignaled event. |
|
||||
| `set(evt)` | Signal the event, waking all waiting tasks. No-op if already set. |
|
||||
| `reset(evt)` | Reset to unsignaled. Panics if tasks are still waiting. |
|
||||
| `isSet(evt)` | Return whether the event is currently signaled. |
|
||||
| `wait(evt)` | `async fn` -- suspend until the event is signaled. If already signaled, yields once (checkpoint) and returns immediately. |
|
||||
|
||||
`Event` implements `Copy`. Cloning an event creates a fresh unsignaled copy with
|
||||
an empty wait queue.
|
||||
|
||||
## Async queues
|
||||
|
||||
Bounded or unbounded queues for passing values between async tasks. When a max
|
||||
size is set, `push` blocks if the queue is full and `pop` blocks if the queue
|
||||
is empty.
|
||||
|
||||
### `LIFOQueue[T]` (stack)
|
||||
|
||||
Last-in, first-out ordering. Backed by a [`seq[T]`](collections.md#sequences):
|
||||
|
||||
```peon
|
||||
var stack = newLIFOQueue[int64](maxSize = 10);
|
||||
|
||||
# Producer task:
|
||||
await stack.push(42);
|
||||
|
||||
# Consumer task:
|
||||
let value = await stack.pop();
|
||||
```
|
||||
|
||||
| Function | Description |
|
||||
|----------|-------------|
|
||||
| `newLIFOQueue[T](maxSize = 0)` | Create a LIFO queue. `maxSize = 0` means unbounded. |
|
||||
| `len(q)` | Return the current number of elements. |
|
||||
| `high(q)` | Return `len - 1`. |
|
||||
| `push(q, v)` | `async fn` -- push a value. Blocks if at capacity. |
|
||||
| `pop(q)` | `async fn` -- pop a value. Blocks if empty. |
|
||||
|
||||
### `FIFOQueue[T]`
|
||||
|
||||
First-in, first-out ordering. Backed by a [`deque[T]`](collections.md#double-ended-queue):
|
||||
|
||||
```peon
|
||||
var queue = newFIFOQueue[int64](maxSize = 10);
|
||||
|
||||
# Producer task:
|
||||
await queue.push(42);
|
||||
|
||||
# Consumer task:
|
||||
let value = await queue.pop();
|
||||
```
|
||||
|
||||
| Function | Description |
|
||||
|----------|-------------|
|
||||
| `newFIFOQueue[T](maxSize = 0)` | Create a FIFO queue. `maxSize = 0` means unbounded. |
|
||||
| `len(q)` | Return the current number of elements. |
|
||||
| `push(q, v)` | `async fn` -- push a value. Blocks if at capacity. |
|
||||
| `pop(q)` | `async fn` -- pop a value. Blocks if empty. |
|
||||
|
||||
Both queue types use [`WaitQueue`](async.md#waitqueue) internally to park and
|
||||
wake tasks.
|
||||
29
docs/manual/stdlib/time.md
Normal file
29
docs/manual/stdlib/time.md
Normal file
@@ -0,0 +1,29 @@
|
||||
# Time
|
||||
|
||||
[Back to Standard Library](index.md) | [Back to Manual](../index.md)
|
||||
|
||||
The `time` module provides CPU time measurement. Import it explicitly:
|
||||
|
||||
```peon
|
||||
import time;
|
||||
```
|
||||
|
||||
## Functions
|
||||
|
||||
| Function | Description |
|
||||
|----------|-------------|
|
||||
| `cpuTime()` | Return elapsed CPU time in seconds as `float64`. |
|
||||
|
||||
Implemented via the C standard library's `clock()` divided by `CLOCKS_PER_SEC`.
|
||||
|
||||
```peon
|
||||
import time;
|
||||
|
||||
let start = cpuTime();
|
||||
# ... do work ...
|
||||
let elapsed = cpuTime() - start;
|
||||
print(elapsed);
|
||||
```
|
||||
|
||||
For async-aware timing (wall-clock sleep, deadlines), see the
|
||||
[async runtime](async.md#timing-and-sleep).
|
||||
138
docs/manual/stdlib/types.md
Normal file
138
docs/manual/stdlib/types.md
Normal file
@@ -0,0 +1,138 @@
|
||||
# Option and Result
|
||||
|
||||
[Back to Standard Library](index.md) | [Back to Manual](../index.md)
|
||||
|
||||
The standard library provides two generic sum types for error handling and
|
||||
optional values, available through the implicit `import std`.
|
||||
|
||||
## `Option[T]`
|
||||
|
||||
```peon
|
||||
type Option[T] = enum {
|
||||
Some { value: T; },
|
||||
None
|
||||
}
|
||||
```
|
||||
|
||||
An optional value: either `Some` containing a value, or `None`.
|
||||
|
||||
### Constructors
|
||||
|
||||
| Function | Description |
|
||||
|----------|-------------|
|
||||
| `some(value)` | Create a `Some` variant wrapping `value`. |
|
||||
| `none(T)` | Create a `None` variant for the given type. Takes a `typevar`. |
|
||||
|
||||
```peon
|
||||
var maybe = some(42);
|
||||
var nothing = none(int);
|
||||
```
|
||||
|
||||
### Methods
|
||||
|
||||
| Function | Description |
|
||||
|----------|-------------|
|
||||
| `get(self)` | Extract the value. Panics on `None`. |
|
||||
| `?` (postfix) | Unwrap `Some` or early-return `None`. See [Operators -- The `?` operator](../operators.md#the--operator-and-pragmatry). |
|
||||
|
||||
### Pattern matching
|
||||
|
||||
```peon
|
||||
match maybe {
|
||||
case Some(v) { print(v); }
|
||||
case None { print("nothing"); }
|
||||
}
|
||||
```
|
||||
|
||||
See [Control Flow -- Pattern matching](../control-flow.md#pattern-matching) for full
|
||||
match syntax.
|
||||
|
||||
## `Result[T, E]`
|
||||
|
||||
```peon
|
||||
type Result[T, E] = enum {
|
||||
Ok { value: T; },
|
||||
Err { error: E; }
|
||||
}
|
||||
```
|
||||
|
||||
A value that is either a successful `Ok` or an error `Err`.
|
||||
|
||||
### Constructors
|
||||
|
||||
| Function | Description |
|
||||
|----------|-------------|
|
||||
| `Ok(value = v)` | Create an `Ok` variant. |
|
||||
| `Err(error = e)` | Create an `Err` variant. |
|
||||
| `Ok()` | Create a void-payload `Ok` (for `Result[void, E]`). |
|
||||
|
||||
```peon
|
||||
let ok: Result[int64, string] = Ok(value = 7);
|
||||
let err: Result[int64, string] = Err(error = "failed");
|
||||
let done: Result[void, string] = Ok();
|
||||
```
|
||||
|
||||
### Methods
|
||||
|
||||
| Function | Description |
|
||||
|----------|-------------|
|
||||
| `unwrap(result)` | Extract the `Ok` value. Panics on `Err`. |
|
||||
| `unwrap(result, msg)` | Extract the `Ok` value. Panics with `msg` on `Err`. |
|
||||
| `?` (postfix) | Unwrap `Ok` or early-return `Err`. See [Operators -- The `?` operator](../operators.md#the--operator-and-pragmatry). |
|
||||
|
||||
```peon
|
||||
print(unwrap(ok)); # 7
|
||||
unwrap(err, "boom"); # Panics with "boom"
|
||||
```
|
||||
|
||||
## The `?` operator
|
||||
|
||||
Both `Option[T]` and `Result[T, E]` carry `#pragma[try]` and support the postfix
|
||||
`?` operator for concise error propagation:
|
||||
|
||||
```peon
|
||||
fn parse(input: string): Option[int64] {
|
||||
# ...
|
||||
}
|
||||
|
||||
fn process(input: string): Option[int64] {
|
||||
let n = parse(input)?; # Unwraps Some, or returns None
|
||||
return some(n + 1);
|
||||
}
|
||||
```
|
||||
|
||||
```peon
|
||||
fn readFile(path: string): Result[string, string] {
|
||||
# ...
|
||||
}
|
||||
|
||||
fn processFile(path: string): Result[int64, string] {
|
||||
let contents = readFile(path)?; # Unwraps Ok, or returns Err
|
||||
return Ok(value = len(contents));
|
||||
}
|
||||
```
|
||||
|
||||
For the full `?` operator semantics and how to define custom try-compatible types,
|
||||
see [Operators -- The `?` operator and `#pragma[try]`](../operators.md#the--operator-and-pragmatry).
|
||||
|
||||
## `AsyncCompletion[T]`
|
||||
|
||||
Returned by [`runAsync(...)`](async.md#runasync):
|
||||
|
||||
```peon
|
||||
type AsyncCompletion[T] = enum {
|
||||
Completed { value: T; },
|
||||
Cancelled
|
||||
}
|
||||
```
|
||||
|
||||
| Function | Description |
|
||||
|----------|-------------|
|
||||
| `unwrap(result)` | Extract the `Completed` value. Panics on `Cancelled`. |
|
||||
|
||||
```peon
|
||||
match runAsync(child()) {
|
||||
case Completed(value) { print(value); }
|
||||
case Cancelled { print("cancelled"); }
|
||||
}
|
||||
```
|
||||
@@ -209,158 +209,17 @@ type Bad = enum {
|
||||
|
||||
## Standard library types
|
||||
|
||||
The standard library provides `Option[T]` and `Result[T, E]`:
|
||||
The standard library provides several important types built on top of the enum and
|
||||
object systems described above. For full API documentation, see the
|
||||
[Standard Library Reference](stdlib/index.md):
|
||||
|
||||
```peon
|
||||
|
||||
var some42 = some(42);
|
||||
var noneInt = none(int);
|
||||
|
||||
let done: Result[void, string] = Ok();
|
||||
|
||||
match done {
|
||||
case Ok { print("done"); }
|
||||
case Err(error) { print(error); }
|
||||
}
|
||||
```
|
||||
|
||||
Both `Option[T]` and `Result[T, E]` support the [`?` operator](operators.md#the--operator-and-pragmatry)
|
||||
for concise error propagation.
|
||||
- [`Option[T]` and `Result[T, E]`](stdlib/types.md) -- sum types for optional values
|
||||
and error handling, with [`?` operator](operators.md#the--operator-and-pragmatry) support
|
||||
- [`array[N, T]`, `seq[T]`, `deque[T]`](stdlib/collections.md) -- static arrays,
|
||||
growable sequences, and double-ended queues
|
||||
- [`Generator`, `Iterator`, `Iterable`](stdlib/iterators.md) -- iterator protocols
|
||||
for [`for` loops](control-flow.md#for-loops)
|
||||
- [`net` module](stdlib/net.md) -- async networking with sockets and address resolution
|
||||
- [`Event`, `LIFOQueue`, `FIFOQueue`](stdlib/sync.md) -- async synchronization primitives
|
||||
|
||||
For pattern matching on enum types, see [Control Flow -- Pattern matching](control-flow.md#pattern-matching).
|
||||
|
||||
### Static arrays
|
||||
|
||||
The built-in `array[N, T]` type constructor creates fixed-size arrays. Arrays can be
|
||||
spelled directly, named with a type alias, or inferred from an array literal:
|
||||
|
||||
```
|
||||
|
||||
type IntVec = array[3, int64];
|
||||
|
||||
var a = IntVec(1, 2, 3);
|
||||
var b = [1, 2, 3, 4]; # Inferred as array[4, int64]
|
||||
|
||||
print(a[0]); # 1
|
||||
a[0] = 9;
|
||||
print(len(a)); # 3
|
||||
print(a[2]); # 3
|
||||
```
|
||||
|
||||
Array access is bounds-checked at runtime when `boundChecks` is enabled
|
||||
(see [Compile-Time Features -- Config symbols](compile-time.md#config-symbols)). Out-of-bounds
|
||||
access panics.
|
||||
|
||||
Plain arrays (non-ref) are value types. Assignment moves the array -- to avoid implicit
|
||||
copies, the source becomes inaccessible after the move:
|
||||
|
||||
```
|
||||
var a = [1, 2, 3];
|
||||
var b = a; # a is moved into b
|
||||
b[0] = 9;
|
||||
# print(a[0]); # Error: a has been moved
|
||||
print(b[0]); # 9
|
||||
```
|
||||
|
||||
To create an independent copy, use `clone` explicitly:
|
||||
|
||||
```
|
||||
var a = [1, 2, 3];
|
||||
var b = clone(a); # Explicit copy
|
||||
b[0] = 9;
|
||||
print(a[0]); # 1 -- a is unchanged
|
||||
```
|
||||
|
||||
Ref arrays are heap-allocated and can be mutably borrowed:
|
||||
|
||||
```
|
||||
type RefVec = ref array[2, int64];
|
||||
|
||||
var a = RefVec(4, 5);
|
||||
var b = mut borrow(a);
|
||||
b[1] = 7;
|
||||
print(a[1]); # 7 -- a and b share the same data
|
||||
```
|
||||
|
||||
### Sequences (`seq[T]`)
|
||||
|
||||
The stdlib provides `seq[T]` as a growable collection:
|
||||
|
||||
```peon
|
||||
|
||||
type Box = object {
|
||||
value: int64;
|
||||
}
|
||||
|
||||
var boxes = @[Box(value = 1), Box(value = 2)];
|
||||
let first: mut lent Box = boxes[0];
|
||||
first.value = 9;
|
||||
|
||||
var ints = @[1, 2, 3];
|
||||
ints[1] = 7;
|
||||
print(ints[1][]); # Scalar reads use whole-deref
|
||||
```
|
||||
|
||||
Important `seq` indexing semantics:
|
||||
|
||||
- `value[index]` returns a borrow, not an owned `T`.
|
||||
- Immutable indexing yields `lent T`.
|
||||
- Indexing through a mutable borrow of `seq[T]` yields `mut lent T`.
|
||||
- `value[index] = newValue` returns `mut lent T`.
|
||||
- `unsafe { value.get_unchecked(index) }` returns the same borrow shapes as
|
||||
`value[index]`, but skips the bounds check for that one access.
|
||||
- When the element is a scalar or you need an owned value, use whole-deref:
|
||||
`value[index][]`.
|
||||
|
||||
`seq[T]` is a runtime collection. It is available in native code, but compile-time
|
||||
evaluation rejects it because CTFE does not permit heap-backed sequence storage.
|
||||
Field access works directly through borrows, so `boxes[0].value` is valid.
|
||||
|
||||
Implementation note: `seq[T]` stores its payload through an internal `buffer:
|
||||
Buffer[T]`
|
||||
owner cell instead of keeping only a raw pointer in the sequence header. This is
|
||||
what allows element borrows and iterator yields to stay tied to the backing
|
||||
storage owner. If growth moves the raw payload, the buffer can swap to a new
|
||||
owner so old element borrows go stale cleanly instead of silently dangling into
|
||||
moved memory.
|
||||
|
||||
Sequences support `append` and standard queries:
|
||||
|
||||
```peon
|
||||
|
||||
var s = @[1, 2, 3];
|
||||
s.append(4);
|
||||
print(len(s)); # 4
|
||||
print(s[3][]); # 4
|
||||
```
|
||||
|
||||
The `@` prefix operator converts a static array to a `seq`:
|
||||
|
||||
```peon
|
||||
var arr = [1, 2, 3];
|
||||
var s = @arr; # seq[int64] with the same elements
|
||||
```
|
||||
|
||||
### Networking (`net`)
|
||||
|
||||
The standard library also provides networking in `net`:
|
||||
|
||||
```peon
|
||||
import net;
|
||||
|
||||
let pair = socketPair(Unix, Stream, 0).unwrap();
|
||||
let addrs = runAsync(getAddrInfo("localhost", 80, Inet, Stream, 0)).unwrap();
|
||||
```
|
||||
|
||||
The public socket-related value types are real enums:
|
||||
|
||||
- `SocketFamily`: `AnyFamily`, `Unix`, `Inet`, `Inet6`
|
||||
- `SocketKind`: `AnyKind`, `Stream`, `Datagram`
|
||||
|
||||
The public address-resolution surface is:
|
||||
|
||||
- `getAddrInfo(host, port)`
|
||||
- `getAddrInfo(host, port, family, kind, protocol)`
|
||||
|
||||
`host` is a `string`, `port` and `protocol` are `int64`, and `family` / `kind`
|
||||
use those enums instead of raw C constants.
|
||||
|
||||
Reference in New Issue
Block a user