Standard Library
The RGC standard library defines the API contract for out-of-the-box functionality, covering built-in cores and standard library modules, with an ecosystem inspired by Python / Rust.
General conventions
- Types use
PascalCase:List,Maybe,Result - Functions and methods use
snake_case:read_file,push - Module names are lowercase:
core,io,math - Variables are mutable by default; containers are passed by move semantics, borrowed with
@/@var
Error handling
- Recoverable errors return
Result[T, Err]— no exceptions, no silent failures - Every fallible API expresses the possibility of failure in its signature
- The
?operator returns early onErrand unwraps the payload onOk
def parse_double(s: str) -> Result[int, str] {
n = s.to_int()?
return Result[int, str].Ok(n * 2)
}
def main() {
match parse_double("21") {
case Ok(n) => print(n) # 42
case Err(e) => print("failed:", e)
}
}
? may only be used in functions returning Result, and the error types must match; supported success payloads are int / float / bool / str / None.
Containers
List[T]
def main() {
list = List[int]()
list.push(1)
list.push(2)
list.clear()
print(list.len()) # 0
}
Maybe[T] and Result[T, Err]
def parse_int(s: str) -> Result[int, str] {
return s.to_int()
}
def main() {
match parse_int("42") {
case Ok(n) => print(n) # 42
case Err(e) => print("failed:", e)
}
}
range
range(n), range(start, end), and range(start, end, step) produce integer sequences for for loops; the end value is excluded, a negative step counts down, and a step of 0 yields no iterations.
def main() {
for i in range(5) {
print(i) # 0 1 2 3 4
}
for i in range(1, 6, 2) {
print(i) # 1 3 5
}
}
File IO
import io
def main() {
print(write_file("/tmp/rgc.txt", "hello\n").is_ok()) # True
print(io.append_file("/tmp/rgc.txt", "world\n").is_ok()) # True
print(io.exists("/tmp/rgc.txt")) # True
print(read_file("/tmp/rgc.txt").unwrap())
print(io.remove_file("/tmp/rgc.txt").is_ok()) # True
}
io follows C-string semantics (content is cut at NUL); use bytes for binary data:
import bytes
def main() {
data = bytes.bytes_new(2)
data.push(0)
data.push(255)
print(bytes.write_bytes("/tmp/rgc.bin", @data).ok) # True
back = bytes.read_bytes("/tmp/rgc.bin")
print(back.ok, back.size, back.data.get(1)) # True 2 255
}
Compression and archiving: gzip.compress_to_file / decompress_file read and write .gz directly; tar.list_entries / extract / create / builder read and write tar (ustar / GNU LongLink / PAX). Combine them for .tar.gz:
import bytes
import gzip
import tar
def main() {
b = tar.builder()
payload = bytes.bytes_from_str("hello\n")
b.add_file("pkg/hello.txt", @payload)
made = b.finish()
archive = made.data
print(gzip.compress_to_file(@archive, "/tmp/pkg.tar.gz", 9).ok) # True
loaded = gzip.decompress_file("/tmp/pkg.tar.gz")
raw = loaded.data
l = tar.list_entries(@raw)
print(l.ok, l.entries.len()) # True 1
}
Formatting
format(fmt, args...) takes a literal format string with {} placeholders supporting int / float / bool / str:
def main() {
name = "RGC"
print(format("hi {}, len = {}", name, name.len())) # hi RGC, len = 3
}
Math
math is a built-in virtual module; abs / min / max / sqrt / pow / floor / ceil can also be called without the prefix.
import math
def main() {
print(math.sqrt(16), math.pow(2, 10)) # 4.000000 1024.000000
print(abs(-5), max(2, 9.5)) # 5 9.500000
}
Time and random
time / random need no source files; import them and call through the module name.
import random
import time
def main() {
start = time.now_monotonic()
time.sleep(0.01)
print("slept", time.now_monotonic() > start) # slept True
random.seed(7) # fixed seed -> reproducible
print("dice", random.random_int(1, 6)) # dice 4
print("unit", random.random_float() >= 0.0) # unit True
}
JSON
json is a lib/json.rg source module for parsing, building, and serializing values. Parse results use JsonParse { ok, error, value }.
import json
def main() {
r = json.parse("{\"name\": \"RGC\", \"stars\": 42, \"tags\": [\"lang\", \"llvm\"]}")
if r.ok {
v = r.value
tags = json.get(@v, "tags")
print(json.as_str(json.get(@v, "name"))) # RGC
print(json.len(@tags)) # 2
print(json.stringify(@v)) # {"name":"RGC","stars":42,"tags":["lang","llvm"]}
} else {
print("invalid json:", r.error)
}
}
Building values:
import json
def main() {
obj = json.object()
json.set(@var obj, "id", json.int_value(7))
xs = json.array()
json.push(@var xs, json.str_value("a"))
json.push(@var xs, json.str_value("b"))
json.set(@var obj, "items", xs)
print(json.stringify(@obj)) # {"id":7,"items":["a","b"]}
}
String escapes support \" \\ \/ \b \f \n \r \t, and \uXXXX (including UTF-16 surrogate pairs). Raw control characters, lone surrogates, and \u0000 are rejected. Numbers follow standard JSON validation and are limited to the i64 range; nesting depth is capped at 256 levels.
Mutate existing children with set_at / remove_at / remove. get returns a copy; for nested structures you can also build the subtree first and set it back.
import json
def main() {
r = json.parse("\"\\u4f60\\u597d\\ud83d\\ude00\"")
v = r.value
print(json.as_str(@v)) # 你好😀
a = json.parse("[1,2,3]")
av = a.value
json.set_at(@var av, 1, json.int_value(20))
ok = json.remove_at(@var av, 0)
print(ok, json.stringify(@av)) # True [20,3]
}
Character code points
chr(cp) converts a Unicode code point to a UTF-8 string (built in, no import needed). Invalid code points (negative, > 0x10FFFF, or surrogate range) panic. chr(0) yields an empty string (strings are NUL-terminated).
def main() {
print(chr(233)) # é
print(chr(20320)) # 你
print(chr(128512)) # 😀
}
Regex
regex is a lib/regex.rg source module: a byte-oriented backtracking engine supporting . * + ? {m} {m,} {m,n} | ( ) (?: ) [ ] [^ ] ^ $ \d \w \s \b \B, backreferences \1–\99, and greedy/lazy quantifiers (*? +? ?? {m,n}?). search returns a ReMatch (ok / start / end / groups, with groups[0] as the whole match); replace expands $1 / ${1} when the pattern has capture groups. Unicode character classes, lookaround, and named groups are not supported.
import regex
def main() {
rx = regex.compile("^(ab)+c?$")
if rx.ok {
print(regex.is_match(@rx, "ababc")) # True
print(regex.is_match(@rx, "abx")) # False
print(regex.replace(@rx, "ababc", "-")) # -
} else {
print("bad pattern:", rx.error)
}
rx2 = regex.compile("ab+")
print(regex.find(@rx2, "xxabbb")) # 2
rx3 = regex.compile("^a{2,3}$")
print(regex.is_match(@rx3, "aaa")) # True
word = regex.compile("\\bcat\\b")
print(regex.is_match(@word, "a cat!")) # True
print(regex.is_match(@word, "concat")) # False
pair = regex.compile("(\\w+)@(\\w+)")
m = regex.search(@pair, "user@host")
if m.ok {
print(m.groups.get(1), m.groups.get(2)) # user host
print(regex.replace(@pair, "user@host", "$2:$1")) # host:user
}
lazy = regex.compile("<(.+?)>")
print(regex.search(@lazy, "<a><b>").groups.get(0)) # <a>
}
System
import os
def main() {
print("home_set", os.getenv("HOME").is_some()) # home_set True
print("cwd_ok", os.getcwd().is_ok()) # cwd_ok True
os.setenv("RGC_DEMO", "1")
os.exit(0)
}
Networking
net is a source module (lib/net.rg) providing synchronous, blocking TCP
(IPv4/IPv6, hostnames, connect/read timeouts, Unix domain sockets). udp
(lib/udp.rg) calls libc through extern def for UDP. http (lib/http.rg)
implements an HTTP client with native http:// and https:// support,
redirects, a keep-alive pool, gzip/deflate with request compression, trailers,
cookies and proxies; HTTPS negotiates HTTP/2 through ALPN by default. http2
(lib/http2.rg) provides the HTTP/2 framing layer, HPACK and flow control.
tls (lib/tls.rg) is a pure-RGC TLS 1.3 client (RFC 8446, no OpenSSL linkage)
with certificate-chain/hostname verification, SNI, ALPN and client certificates
(mTLS); https (lib/https.rg) is a compatibility layer, and gzip
(lib/gzip.rg) implements DEFLATE/gzip/zlib in pure RGC
(CRC-32/Adler-32, multi-member, stored/fixed/dynamic blocks) with no zlib dependency.
The SHA-2, HKDF, AES-GCM, ChaCha20-Poly1305, X25519, P-256, RSA and ASN.1/X.509
building blocks are all source modules under lib/, so no external crypto
library is linked. Built-in tcp_* primitives call libc sockets directly.
import net
def main() {
l = net.listen("127.0.0.1:0") # port 0: kernel-assigned port
if not l.ok {
print("listen failed:", l.error)
return
}
listener = l.listener
port = listener.local_port()
c = net.connect_to("127.0.0.1", port)
if not c.ok {
print("connect failed:", c.error)
return
}
client = c.stream
a = listener.accept()
if not a.ok {
print("accept failed:", a.error)
return
}
server = a.stream
client.send("ping")
r = server.recv(64)
print(r.ok, r.value) # True ping
server.send("pong")
r2 = client.recv(64)
print(r2.ok, r2.value) # True pong
client.close()
server.close()
listener.close()
}
Behavior:
- Addresses:
net.connect("host:port")/net.listen("host:port"), or the structuredconnect_to(host, port)/listen_on(host, port). Hostnames are resolved withgetaddrinfo(IPv4/IPv6; IPv6 literals use"[::1]:8080"). Port0is only valid for listening (ephemeral port). - Timeouts:
connect_timeout(addr, ms)/connect_to_timeout(host, port, ms)bound connection setup;TcpStream.set_timeout(ms)andTcpListener.accept_timeout(ms)bound I/O. Timeouts reporttimeout. sendblocks until every byte is written and returns the number of bytes sent. On EOFrecv(max)returnsok=True, value=""; real socket errors returnok=Falsewith thestrerrortext. Usesend_bytes/recv_bytes(Bytes) for binary data.- Unix domain sockets:
connect_unix(path)/listen_unix(path)(abstract addresses start with@). - Connect/listen/accept results use
TcpConnect/TcpListen/TcpAccept/TcpRecvwrapper classes (Resultdoes not yet support custom payloads). - Peers closing early cannot raise SIGPIPE (sends use
MSG_NOSIGNAL).
UDP
import udp
def main() {
b = udp.open("127.0.0.1:0") # port 0: kernel-assigned port
if not b.ok {
print("bind failed:", b.error)
return
}
s = b.sock
s.send_to("ping", "127.0.0.1", s.local_port())
r = s.recv_from(1024)
print(r.ok, r.data, r.host, r.port) # True ping 127.0.0.1 <port>
s.close()
}
udp.open("host:port") / open_on(host, port) bind a local address
(IPv4/IPv6/hostname). send_to(data, host, port) / send_bytes(data, host, port)
send one datagram and recv_from(max) blocks for one datagram
(UdpRecv{ok,error,data,data_bytes,host,port}). Datagram boundaries are
preserved; an empty datagram returns ok=True, data="", and payloads larger
than max are truncated. data is a C string (strlen semantics, truncated at
NUL); use data_bytes for binary payloads. set_timeout(ms) bounds sends and
receives and reports ok=False, error="timeout".
The HTTP client comes as one-shot module functions and a configurable
HttpClient:
import http
def main() {
r = http.get("https://example.com/") # http:// and https://
if not r.ok {
print("request failed:", r.error)
return
}
res = r.response
print(res.status) # 200
print(res.version, res.url)
print(http.header(@res, "Content-Type"))
print(res.body.len(), res.body_bytes.len) # binary bodies use body_bytes
p = http.post("http://127.0.0.1:8080/echo", "hello")
print(p.ok, p.response.status)
# connection reuse + custom headers + cookies + proxy
c = http.new_client()
c.headers.push("X-Token: secret")
c.set_proxy("http://127.0.0.1:3128")
a = c.get("http://service.invalid/a")
b = c.get("http://service.invalid/b") # same keep-alive connection
c.close()
}
HttpResponse has status / version / headers: List[str] /
trailers: List[str] / body: str / body_bytes: Bytes / url: str.
http.header(res, name) is case-insensitive and returns an empty string when
missing (@ only applies to variables, so assign res = r.response first);
chunked trailers are available through http.trailer(res, name).
HttpClient defaults: timeout_ms=30000, connect_timeout_ms=10000,
max_redirects=10, max_body=32 MiB, max_header=64 KiB, max_idle=8,
verify_tls=True, http2=True, keep_alive=True, follow_redirects=True,
compress_request=False. It supports:
- arbitrary methods via
get/post/request/get_with/post_with/request_with/request_bytes(binary request bodies); - redirects: 301/302/303 turn non-GET/HEAD into GET, 307/308 preserve method
and body, cross-host hops drop
AuthorizationandHost, relativeLocationvalues merge per RFC 3986; - a keep-alive connection pool, automatic
gzip/deflatedecompression, trailer exposure, a cookie jar (Domain/Path/Secure/Max-Age), 1xx skipping, and no body forHEAD/204/304; - request-body compression (
compress_request=Truegzips the body and sendsContent-Encoding: gzip); - HTTP proxies (absolute-form for plaintext, CONNECT tunnels for HTTPS with
Proxy-Authorization); - client certificates via
client_cert/client_keyorset_client_cert(cert, key); - limits (
response body too large/response header too large) and timeouts (timeout); - query strings via
http.encode_query(pairs)/http.decode_query(q)andurl_encode/url_decode; - async entry points
http.get_async/post_async/request_async, which returnTask[HttpResult](one thread per task) and work withasyncio.gather/asyncio.wait_any.
HTTP/2
HTTPS requests offer h2 through ALPN by default. When the server selects it
the client uses HTTP/2 (res.version == "HTTP/2", trailers still land in
res.trailers); otherwise it falls back to HTTP/1.1. Set c.http2 = False to
disable negotiation. HTTP/2 is TLS-only (no h2c) and does not support server
push. HttpClient reuses a connection sequentially; to run concurrent GETs on
one connection, use the low-level http2.get_many (it honors the server's
MAX_CONCURRENT_STREAMS and isolates per-stream failures).
import http
def main() {
c = http.new_client()
r = c.get("https://example.com/")
if r.ok {
print(r.response.version) # HTTP/2 or HTTP/1.1
print(r.response.status)
}
c.close()
}
For manual connection management or HPACK/frame coding, import http2 directly:
import http2
def main() {
c = http2.connect("example.com", 443, 10000, True, "", "", "")
if not c.ok {
print("connect failed:", c.error)
return
}
hs = List[str]()
hs.push("user-agent: rgc-demo")
conn = c.conn
r = http2.request(conn, "GET", "https", "example.com", "/", hs,
"", 0, False, 65536, 33554432)
if r.ok {
print(r.status, r.body.len) # 200 <bytes>
}
# Concurrent multiplexing (GET only); responses follow the paths order.
paths = List[str]()
paths.push("/a")
paths.push("/b")
rs = http2.get_many(conn, "https", "example.com", paths, hs, 65536, 1048576)
if rs.ok {
i = 0
while i < rs.responses.len() {
one = rs.responses.get(i)
print(i, one.ok, one.status, one.body.len)
i = i + 1
}
}
conn.close()
}
Low-level API: http2.connect / attach / request / get_many,
encode_request_headers / encode_response_headers / encode_trailers,
new_decoder / decode_block, and encode_frame. The implementation covers
SETTINGS/PING/WINDOW_UPDATE/GOAWAY/RST_STREAM, HEADERS/CONTINUATION/DATA,
HPACK (static table + dynamic table + Huffman decoding) and connection/stream
flow control. get_many dispatches frames per stream and enforces per-stream
limits and cancellation.
HTTPS / TLS
http already supports https:// natively (TLS comes from lib/tls.rg); the
https module is a compatibility layer: https.get / https.post delegate to
http, while get_insecure / post_insecure disable certificate verification.
import http
import https
import tls
def main() {
r = https.get("https://example.com/")
if r.ok {
print(r.response.status) # 200
print(http.header(@r.response, "Content-Type"))
} else {
print("request failed:", r.error) # certificate/network error
}
# self-signed / local testing: skip certificate verification
local = https.get_insecure("https://127.0.0.1:8443/")
print(local.ok)
# low-level TLS
c = tls.connect("example.com", 443, 10000, True)
if c.ok {
s = c.conn
s.send("GET / HTTP/1.1\r\nHost: example.com\r\n\r\n")
print(s.recv(4096).value)
s.close()
}
}
https.get / https.post verify the certificate chain and host identity
(SNI for DNS names, IP verification for literals) and report the certificate
error reason on failure. get_insecure / post_insecure skip verification.
The lower-level tls.connect(host, port, timeout_ms, verify) returns
TlsResult{ok,error,conn}; TlsConn provides send / recv /
recv_bytes / get_version / close, and tls.connect_with_ca accepts a
PEM CA file. tls.connect_mtls / connect_on_mtls send a client certificate
(cert_file / key_file, where an empty key_file reuses the certificate
file); tls.connect_alpn / connect_on_alpn offer ALPN during the handshake
and TlsConn.get_alpn() returns the negotiated protocol (h2 / http/1.1).
HttpClient enables mTLS through client_cert / client_key /
set_client_cert. Override the system CA with SSL_CERT_FILE /
SSL_CERT_DIR. The https module accepts only https:// (default port 443).
Not implemented: TLS session-resumption knobs and an async streaming client (
awaitis not yet wired to the event loop, see "Event loop"). Concurrent HTTP/2 multiplexing is available throughhttp2.get_many(GET only).
Async
An async def function, when called, immediately spawns a thread and returns a
Task[T]. await waits for the task and yields its result; it is only allowed
inside async functions. asyncio.run(task) waits synchronously from an ordinary
function. asyncio.gather(tasks) waits for a group of tasks and collects their
results in input order; asyncio.wait_any(tasks) returns the index of the first
completed task (or -1 for an empty list) without consuming any task;
task.done() reports whether a task has finished;
task.wait(ms) waits up to the given number of milliseconds, returning False
on timeout without consuming the task; task.cancel() requests cooperative
cancellation, observed inside the task with asyncio.cancelled().
import asyncio
import time
async def add_async(a: int, b: int) -> int {
time.sleep(0.02)
return a + b
}
async def slow() -> int {
time.sleep(0.25)
return 1
}
async def cancellable() -> int {
i = 0
while i < 100 {
if asyncio.cancelled() {
return -1
}
time.sleep(0.01)
i = i + 1
}
return 0
}
async def driver() {
t = add_async(40, 2)
print(await t) # 42
a = slow()
b = slow()
print((await a) + (await b)) # 2, ~0.25s total
tasks = List[Task[int]]()
tasks.push(add_async(1, 2))
tasks.push(add_async(3, 4))
print(await tasks.get(0), await tasks.get(1)) # 3 4
ts = List[Task[int]]()
ts.push(slow())
ts.push(slow())
print(ts.get(0).done()) # usually False
vals = await asyncio.gather(ts) # parallel wait, results in input order
print(vals.len()) # 2
wa = List[Task[int]]()
fa = cancellable() # slow task that observes cancellation
fb = add_async(1, 2) # fast task
wa.push(fa)
wa.push(fb)
idx = asyncio.wait_any(wa) # 1: fast task finished first; tasks not consumed
print(idx, await wa.get(idx)) # 1 3
fa.cancel() # cancel the remaining task
print(await fa) # -1
w = slow()
print(w.wait(100)) # False: not done within 100ms
print(w.wait(1000)) # True: waited long enough
print(await w) # 1: wait does not consume the task
c = cancellable()
print(c.cancel()) # True: request recorded
print(c.cancelled()) # True
print(await c) # -1: task exits at a checkpoint
}
def main() {
asyncio.run(driver())
print(asyncio.run(add_async(20, 22))) # 42
}
Behavior:
Task[T]is a built-in generic class (handlefield); it can only be created by calling an async function.await/asyncio.gatherconsume tasks: aTaskvariable may be awaited only once; dropping an un-awaited task leaks its result box (reclaimed at process exit).asyncio.gathertakes aList[Task[T]]variable (consumed by the call) and returnsTask[List[T]], which can be awaited or passed toasyncio.run; an empty list yields an empty list.asyncio.wait_anytakes aList[Task[T]], polls the completion flags and returns the index of the first completed task (in list order; retries about every 1ms while none is done), or-1for an empty list. It consumes neither the tasks nor the list, so they can still be awaited, cancelled or queried with anotherwait_anyafterwards.task.done()reads the completion flag atomically without blocking; afterawaitthe task variable has been consumed and can no longer be queried.task.wait(ms)polls the completion flag:Truewhen the task finishes,Falseon timeout (ms <= 0checks once). It does not consume the task and can still be awaited afterwards; it gives up waiting without cancelling the task.task.cancel()records a cooperative cancellation request, returning whether it was newly recorded (Falseif already done or already requested); it does not kill the thread or consume the task.task.cancelled()reads the request flag andasyncio.cancelled()reads the current task's flag (Falseoutside a task); tasks must poll it and return at a safe point, and tasks that ignore it run to completion (the Go / C# cooperative model).- Payloads may be scalars,
stror custom classes; nested await,Task[int]annotations andList[Task[int]]all work. - Limits: no
async def main, no async methods, no borrow parameters/returns; cancellation is cooperative; timeouts usewaitpolling; one thread per task, so the task count is bounded by the thread limit;List/Mapwrites are not synchronized across threads. An event loop is provided by the separateeventmodule (see below), but it is not wired toawaityet.
Implementation: one thread per task (pthread); user programs link
-lpthread.
Event loop (event)
event is a single-threaded selector built on Linux epoll: timers use timerfd
and cross-thread wakeups use a socketpair, all through extern def calls to
libc. It is independent of the thread-per-task async model and is meant for
waiting on many file descriptors at once.
import event
import net
def main() {
loop = event.new_loop()
if not loop.is_open() {
print(loop.error)
return
}
l = net.listen_on("127.0.0.1", 8080)
listener = l.listener
listener.set_nonblocking(True)
loop.add(listener.fd, 1, event.ev_in())
while True {
w = loop.wait(-1) # <0 blocks forever, 0 polls once
i = 0
while i < w.events.len() {
e = w.events.get(i)
if e.token == 1 {
a = listener.try_accept()
if a.ok and not a.again {
s = a.stream
s.set_nonblocking(True)
# register read/write interests and serve the request
}
}
i = i + 1
}
}
}
event.new_loop()creates the epoll instance and wakeup channel;add(fd, token, events)/modify/removemanage registrations. Combineev_in()/ev_out()/ev_err()/ev_hup()/ev_rdhup()/ev_edge()with|.wait(timeout_ms)returns up to 64Event{token, events}values per call; kernel events carry only the token, so callers map tokens back to state.- Timers:
add_timer(token, delay_ms)one-shot,add_interval(token, interval_ms)periodic,cancel_timer(token)andtimer_count(); fired events carryev_timeout(). - Wakeups:
loop.post(token)from the loop thread,event.post_fd(loop.wake_w, token)from another thread;waitreturnsev_wake()plus the token. - Non-blocking IO: pair it with
net.connect_start/connect_finish,TcpListener.try_accept,TcpStream.try_recv/try_sendandudp.UdpSocket.try_recv_from/try_send_to;again=TruemeansEAGAIN, distinguishing it from a real error. - Limits: Linux only; at most 64 events per
wait; tokens are0..2^62-1and must be unique within a loop; control operations should run on the thread callingwait(post/post_fdare thread-safe).
Module overview
| Module / category | Contents |
|---|---|
core | built-in types, basic operations, to_string, chr, format |
io | input/output, file read/write/append/exists/remove, printing |
math | abs / min / max / sqrt / pow / floor / ceil |
time | now_monotonic / now / sleep |
random | seed / random_int / random_float |
os | exit / getenv / setenv / getcwd / system |
json | parse / stringify / builders / accessors / mutation |
regex | compile / is_match / find / search / replace |
bytes | binary buffers (bytes_new / bytes_from_str / push / get / slice / append ...) and binary-safe file I/O (read_bytes / write_bytes) |
net | TCP: synchronous connect / connect_to / connect_timeout / listen / listen_on / resolve / connect_unix / listen_unix, TcpStream / TcpListener (IPv4/IPv6, timeouts, binary); non-blocking connect_start / connect_finish, try_accept / try_recv / try_send / set_nonblocking |
udp | UDP: synchronous open / open_on, UdpSocket.send_to / send_bytes / recv_from / set_timeout / local_port / close; non-blocking try_recv_from / try_send_to / set_nonblocking (IPv4/IPv6, binary) |
http | HTTP client (incl. HTTPS, negotiates HTTP/2 by default): get / post / request / request_bytes, HttpClient (redirects, keep-alive, gzip/request compression, trailers, cookies, proxy, mTLS, limits, timeouts, http2 switch) |
http2 | HTTP/2 over TLS ALPN: connect / attach / request / get_many (concurrent GET multiplexing), HPACK coding (new_decoder / decode_block / encode_*), encode_frame; flow control and trailers |
https / tls | https is a compatibility layer over http (get / post / get_insecure / post_insecure); tls.connect / connect_mtls / connect_alpn, TlsConn (pure-RGC TLS 1.3, incl. client certificates and ALPN) |
| crypto | pure RGC: sha2 (SHA-256/384/512), hmac, hkdf, aes (AES-128/256-GCM), chacha20poly1305, x25519, p256 (P-256/P-384 ECDH/ECDSA), rsa (PKCS#1 v1.5/PSS), bigint, entropy; ASN.1/X.509: asn1, pkey, x509 (chain verification and system CAs) |
gzip | gzip compression/decompression: compress / decompress / decompress_limit / decompress_mem / is_gzip / is_zlib (pure RGC DEFLATE, stored/fixed/dynamic, multi-member); file-level compress_to_file / decompress_file / decompress_file_limit |
tar | tar archives: list_entries / extract / create / builder (ustar, GNU LongLink, PAX; pair with gzip for .tar.gz) |
asyncio | async: async def / await / asyncio.run / asyncio.gather / asyncio.wait_any / asyncio.cancelled / Task.done / Task.wait / Task.cancel, Task[T] (pthread) |
event | event loop: new_loop / add / modify / remove / wait / add_timer / add_interval / cancel_timer / post / post_fd / close (epoll + timerfd + socketpair) |
string | trim / find / replace / to_upper / to_lower / pad_left |
list | sum_ints / min_int / max_int / sort_ints / sort_strs / join_ints |
path | path checks / joining / directory and file names |
| error handling | Result[T, Err], ? propagation, match |
| sequences | range(n) / range(start, end[, step]) |
| utilities | string processing, collection operations |
Error handling principles
- Recoverable errors always return
Result; silent failures are prohibited. - Programmer errors (e.g., out-of-bounds indexing) abort with a diagnostic message.