Standard library
The standard library lives in std/ as ordinary Xi modules that wrap C runtime
primitives. Import a module and call it through its namespace:
import "std/math.xi"
import "std/text.xi"
import "std/log.xi"
async entry (logger: Logger) main(args: String[]) -> Integer {
logger.info("sqrt(2) = " + math.sqrt(2.0))
logger.info(text.toUpper("hello"))
return 0
}
Import everything at once with import "std/all.xi".
Resolving imports
import "std/<mod>.xi" is resolved first relative to the importing file, then
relative to $XC_STD. The installed toolchain points XC_STD at its bundled
standard library automatically, so import "std/..." just works:
$ xc myapp.xi
Which module do I want?
This page is the API reference - every module and its functions. Several modules have a guide of their own that explains the design; start there if you are learning, and come back here to look up a signature.
| I want to… | Module | Guide |
|---|---|---|
| work with lists, sets, maps, sequences | collections | Collections |
| read or write JSON / YAML / XML | json, yaml, xml | Serialization |
| query a data source | query, sql | Query |
| put a repository over a data source | data | Repository |
| serve HTTP | web | Web |
| publish and subscribe to events | events | Events |
| report health and metrics | monitoring | Monitoring |
| run work concurrently | thread | Threading |
| hash, sign, encode | crypto | - |
| read files, paths, env, processes | fs, path, process | - |
| make HTTP calls / open sockets | http, net | - |
| numbers, text, bytes, time, conversion | math, text, bytes, time, convert | - |
| print and read from the console | io | - |
| call C | (extern "C") | FFI |
Modules
math - std/math.xi
| Function | Signature |
|---|---|
pi, e | () -> Number |
abs, sqrt, exp, ln, log10 | (Number) -> Number |
sin, cos, tan | (Number) -> Number |
floor, ceil, round | (Number) -> Number |
pow | (Number, Number) -> Number |
min, max | (Number, Number) -> Number |
clamp | (Number, Number, Number) -> Number |
text - std/text.xi
| Function | Signature |
|---|---|
length | (String) -> Integer |
charAt | (String, Integer) -> Integer (code point, -1 out of range) |
substring | (String, Integer, Integer) -> String |
trim, toUpper, toLower | (String) -> String |
startsWith, endsWith, contains | predicate (String, String) |
indexOf | (String, String) -> Integer (-1 if absent) |
repeat | (String, Integer) -> String |
replace | (String, String, String) -> String (all occurrences) |
isEmpty | predicate (String) |
split, join | (String, String) -> String[] / (String[], String) -> String |
isAlpha, isDigit, isAlnum, isSpace | predicate (Integer) - classify a char code (e.g. from charAt) |
indexOfChar | (String, Integer) -> Integer - first index of a char code (-1 if absent) |
fromCharCode | (Integer) -> String - a one-character string from a char code |
bytes - std/bytes.xi
Bytes is a primitive type: a raw byte buffer, distinct from String. Like
String it is an immutable value (copies share the buffer; producers
heap-allocate a fresh one). Used for binary I/O.
| Function | Signature |
|---|---|
length | (Bytes) -> Integer |
at | (Bytes, Integer) -> Integer (byte 0..255, -1 out of range) |
slice | (Bytes, Integer, Integer) -> Bytes ([from, to)) |
concat | (Bytes, Bytes) -> Bytes |
fromString | (String) -> Bytes |
toString | (Bytes) -> String |
empty | () -> Bytes |
isEmpty | predicate (Bytes) |
convert - std/convert.xi
| Function | Signature |
|---|---|
toString | (Number) -> String |
intToString | (Integer) -> String |
boolToString | (Bool) -> String |
parseNumber | (String) -> Number! |
parseInteger | (String) -> Integer! |
parseNumber/parseInteger return a result:
let r = convert.parseInteger("42")
if isOk(r) { system.stdout.writeln("got " + r.value) }
json - std/json.xi
Xi's serialization library. Json is an opaque value tree; build it with the
constructors, compose with set/push, render with stringify/pretty, and
read text back with parse. See Serialization for the full
guide.
| Function | Signature |
|---|---|
nul | () -> Json |
of | (Bool) -> Json |
num / int | (Number) -> Json / (Integer) -> Json |
str | (String) -> Json |
array, object | () -> Json |
push | (Json, Json) -> Json (append to array; returns it) |
set | (Json, String, Json) -> Json (set object key; returns it) |
stringify, pretty | (Json) -> String |
parse | (String) -> Json (check with isValid) |
isValid | predicate (Json) |
kind, length | (Json) -> Integer |
isNull … isObject | predicate (Json) |
at | (Json, Integer) -> Json (array element) |
get, has, keyAt | object access |
asString, asNumber, asBool | leaf coercion |
getString, getNumber | (Json, String) -> … (field shortcut) |
yaml - std/yaml.xi
YAML over the same Json tree (block style). See Serialization.
| Function | Signature |
|---|---|
stringify | (Json) -> String |
parse | (String) -> Json |
xml - std/xml.xi
XML over the same Json tree (object → child elements, array → repeated element,
scalar → text). See Serialization.
| Function | Signature |
|---|---|
stringify | (Json) -> String (wraps in <root>) |
stringifyAs | (Json, String) -> String (custom root tag) |
parse | (String) -> Json |
crypto - std/crypto.xi
Self-contained hashing, HMAC, encodings, and a CSPRNG - no external libraries.
Digests are Bytes; render with hex/base64. (Test-vector verified.)
| Function | Signature |
|---|---|
sha256 / sha1 / md5 | (Bytes) -> Bytes (digest) |
sha256Hex / sha1Hex / md5Hex | (String) -> String (hex digest of text) |
hmacSha256 | (Bytes, Bytes) -> Bytes (key, msg) |
hmacSha256Hex | (String, String) -> String |
hex / fromHex | (Bytes) -> String / (String) -> Bytes |
base64 / fromBase64 | (Bytes) -> String / (String) -> Bytes |
randomBytes / randomHex | (Integer) -> Bytes / (Integer) -> String (from /dev/urandom) |
web - std/web.xi
A tiny REST framework over HTTP/1.1: implement WebRequestHandler, route by
overloading handle with where guards, and run web.serve. Payloads
auto-(de)serialize via a WebTransport (JSON by default). See Web.
| Name | Kind / Signature |
|---|---|
WebRequestHandler | interface - action handle(req: HttpRequest, res: HttpResponse) |
WebTransport | interface - serialize(Json) -> String / deserialize(String) -> Json (JSON default) |
req.path / req.method / req.body | HttpRequest -> String |
req.query("q") / req.header("X") | (HttpRequest, String) -> String |
req.parse(T) | deserialize the body into a T |
res.send(dto) | serialize dto and reply 200 |
res.sendStatus(code, msg) / res.sendText(code, body) | plain-text reply |
web.serve | (Integer) - run a blocking HTTP/1.1 server |
web.serveTLS | (Integer, String, String) - HTTPS (cert, key); build with XC_TLS=1 |
web.serveHttp2 | (Integer, String, String) - HTTP/2 over TLS (ALPN h2); build with XC_HTTP2=1 |
web.shutdown | () - stop a running server (safe from another thread) |
query - std/query.xi
Query: reified query plans and the provider contract. A chain rooted at
query.from<T>("source") compiles to a QueryPlan value; collect(provider)
runs it. See Query.
| Name | Kind / Signature |
|---|---|
query.from<T>("src") | root a query at a named source |
list.asQuery() / arr.asQuery() | root a query at an in-memory collection; run with .toList() |
.using(p) | bind a provider to the query so terminals run against it |
.collect(p) / .collect() / .toList() / .first() | run: explicit / bound / bound / first row (T?) |
QueryProvider | interface - name() -> String (identity, for where selection) + run(plan) -> Json (read) + insert / remove (write) |
RowStore | interface - load(name: String, rows: Json) |
MemorySource | class - the in-memory reference provider (implements both) |
QueryPlan / QueryStage / QueryExpr | the plan's types - walk with match; serialize with as Json |
someList.asQuery() … .toList() | root a query at a List<T>/T[] and run it locally |
sql - std/sql.xi
Render a QueryPlan to a SQL statement with bound parameters. Dialects are
an interface - three are bundled; add your own without touching std.
| Name | Kind / Signature |
|---|---|
sqlRender | (QueryPlan, SqlDialect) -> SqlStatement! |
SqlStatement | { text: String, params: Json } |
SqlDialect | interface - name / placeholder / quoteIdent / callSql / regexpExpr / limitSql |
SqliteDialect / PostgresDialect / MysqlDialect | bundled dialects (.name() -> "sqlite" / "postgres" / "mysql") |
data - std/data.xi
Standard repository interfaces over any QueryProvider. Implement
getProvider() and source(); findAll / findById / save / delete /
deleteById and entity ↔ model conversion are overridable defaults. Reads return
a composable Query bound to the repo's provider. See
Repository.
| Name | Kind / Signature |
|---|---|
Repository<TKey, TEntity, TModel> | interface - implement getProvider() / source(); default findAll / findById / convertTo / convertFrom |
CrudRepository<TKey, TEntity, TModel> | interface - extends Repository with default save / delete / deleteById |
monitoring - std/monitoring.xi
A mechanism for monitoring, decoupled from what it watches: implement
Monitoring and the registry loops over it. Off by default - enable it from
main. Each subsystem is a separate import beside its own module. See
Monitoring.
| Name | Kind / Signature |
|---|---|
Monitoring | interface - name() / startMonitor() / healthy() -> Bool / metrics() -> Json |
MonitoringRegistry | interface - enable() / isEnabled() / report() -> Json / health() -> Json / healthy() -> Bool |
monitor.rss() / monitor.peakRss() | () -> Integer - resident / peak bytes |
monitor.uptimeMs() | () -> Integer - since process start |
monitor.info(n) | (Integer) -> String - module id (0) / name (1) / version (2) |
monitor.status(name, up) / monitor.gauge(name, n) | report a status / number directly |
monitor.snapshot() | () -> Json - uptime + reported gauges |
MemoryMonitoring / CpuMonitoring | std/monitoring/memory.xi / .../cpu.xi |
WebMonitoring + MonitorController | std/monitoring/web.xi - numbers + /monitor/* endpoints |
QueryMonitoring / ThreadMonitoring | std/monitoring/query.xi / .../thread.xi |
thread - std/thread.xi
Share-nothing threads + channels. A parallel block runs on a new OS thread
and yields a Thread handle; threads communicate only through thread-safe
channels, which carry strings or structured values. See Threading.
| Name | Kind / Signature |
|---|---|
thread.channel() | () -> Channel (thread-safe FIFO) |
ch.send(x) | String as-is; a structured event/type is JSON-serialized; numbers/bools stringify |
ch.recv() / ch.recv(T) | raw String / deserialize a structured T (blocks) |
ch.close() | (Channel) - wakes a blocked recv |
parallel [(caps…)] { … } | spawn a thread, evaluates to a Thread (captures must be channels) |
thread.stopped() | () -> Bool - inside a block, has stop been requested? |
t.stop() / t.wait() / t.running() | request stop / join / Bool liveness |
events - std/events.xi
Built-in typed publish/subscribe. A producer publishes any DTO under a topic
through an injected PublisherService; a listener subscribes to a topic and
receives the typed DTO - no JSON. The default MemoryBus/MemoryConsumer
queue events in memory and pass the typed value through without serialization;
bind your own transport to go external (serialize on publish, deserialize on
receive). See Events.
| Name | Kind / Signature |
|---|---|
event T { … } | a typed event DTO (publishable; gets a derived codec) |
events.publish(topic, dto) | publish any DTO under a topic (via PublisherService) |
listener f(e: T) on "topic" | typed subscriber for a topic |
PublisherService | interface { producer publish(e: Event) } - outbound transport |
ConsumerService | interface { consumer run() } - the delivery pump |
MemoryBus / MemoryConsumer | defaults: in-memory queue, no serialization |
Events.run() | run the pump synchronously (resolve + run the ConsumerService) |
Events.runAsync() / Events.stop() | deliver on a worker thread (returns a Thread) / close the queue to stop it |
Events.dispatch(e) | deliver an envelope to its typed listeners |
Events.encode(e) / Events.decode(topic, type, json) | codec helpers for transports |
Events.topic(e) / Events.type(e) | envelope accessors |
io - std/io.xi
| Function | Signature |
|---|---|
println, print, eprintln | consumer (String) |
readLine | () -> String |
eof | predicate () |
config - std/config.xi
Typed configuration: bind I -> readConfig("app.yaml") makes the compiler
synthesize an implementor of interface I that loads the file once and
deserializes each method's value from the matching key. See
Configuration.
log - std/log.xi
A leveled Logger interface with a ConsoleLogger default (DI picks it as the
sole implementor). Inject Logger anywhere deps are wired - classes, functions,
and entry - and bind your own implementor to redirect output.
| Method | Level / Destination |
|---|---|
print(msg) | unprefixed line → stdout |
debug(msg) | [debug] → stdout |
info(msg) | [info] → stdout |
warn(msg) | [warn] → stderr |
error(msg) | [error] → stderr |
fatal(msg) | [fatal] → stderr |
audit(msg) | [audit] → stdout (security/compliance trail) |
ConsoleLogger is the default implementor; bind your own Logger (file,
structured JSON, a test buffer, …) to redirect any of these.
fs - std/fs.xi
| Function | Signature |
|---|---|
exists, isDir, isFile | predicate (String) |
readFile | (String) -> String! (Err if missing) |
readBytes | (String) -> Bytes! (Err if missing) |
writeFile | (String, String) -> Bool |
writeBytes | (String, Bytes) -> Bool |
appendLine | (String, String) -> Bool |
size | (String) -> Integer! (bytes; Err if missing) |
modifiedTime | (String) -> Integer! (epoch seconds) |
remove, mkdir, mkdirAll | (String) -> Bool |
rename, copy | (String, String) -> Bool |
cwd | () -> String |
listDir | (String) -> String[] (names; empty if not a dir) |
path - std/path.xi
Pure-Xi path string helpers (no I/O).
| Function | Signature |
|---|---|
join | (String, String) -> String |
dirname | (String) -> String ("." if none) |
basename | (String) -> String |
ext | (String) -> String (incl. dot, "" if none) |
stripExt | (String) -> String |
net - std/net.xi
Blocking TCP sockets, client and server. Conn and Listener wrap a socket
file descriptor. Data is sent/received as Bytes (with *Text convenience
helpers). Listen on port 0 for an OS-assigned port, then read it with port.
| Function | Signature |
|---|---|
dial | (String, Integer) -> Conn! (host, port) |
listen | (Integer) -> Listener! |
accept | (Listener) -> Conn! (blocks) |
port | (Listener) -> Integer |
send / recv | (Conn, Bytes) -> Integer / (Conn, Integer) -> Bytes |
sendText / recvText | (Conn, String) -> Integer / (Conn, Integer) -> String |
close | consumer (Conn) |
closeListener | consumer (Listener) |
http - std/http.xi
A minimal HTTP/1.1 client over net. http:// always works; https:// needs the toolchain built with XC_TLS=1. A
Response is { status: Integer, headers: String, body: String }, where
headers is the raw CRLF-separated header block; look one up with header.
| Function | Signature |
|---|---|
get | (String) -> Response! |
post | (String, String, String) -> Response! (url, body, contentType) |
request | (String, String, String, String) -> Response! (method, url, body, contentType) |
header | (Response, String) -> String (case-insensitive; "" if absent) |
parseUrl | (String) -> Url! ({host, port, path, tls}; supports http:// and https://) |
parseResponse | (String) -> Response! |
import "std/http.xi"
let r = http.get("http://example.com/")
if isOk(r) {
system.stdout.writeln("status " + r.value.status)
system.stdout.writeln(r.value.body)
}
proc - std/process.xi
| Function | Signature |
|---|---|
env | (String) -> String (empty if unset) |
envOr | (String, String) -> String |
run | (String) -> Integer (shell command exit) |
exit | consumer (Integer) |
time - std/time.xi
| Function | Signature |
|---|---|
nowNanos, nowMillis | () -> Integer (monotonic) |
sleepMs | consumer (Integer) |
How it's built
Each module declares the C primitives it needs via extern "C" (e.g.
xstd_sqrt, xstd_trim) and exposes a clean, namespaced API. The primitives
live in runtime/runtime.c. Because modules use namespace, two modules can
expose the same short name without colliding - see
Multi-file projects.
!!! note "Collections"
Generic containers (List<T>, Map<K,V>) await generics (monomorphization)
and are not in the library yet. Use T[] arrays with for … in for now.