Skip to main content

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 on Err and unwraps the payload on Ok
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 structured connect_to(host, port) / listen_on(host, port). Hostnames are resolved with getaddrinfo (IPv4/IPv6; IPv6 literals use "[::1]:8080"). Port 0 is only valid for listening (ephemeral port).
  • Timeouts: connect_timeout(addr, ms) / connect_to_timeout(host, port, ms) bound connection setup; TcpStream.set_timeout(ms) and TcpListener.accept_timeout(ms) bound I/O. Timeouts report timeout.
  • send blocks until every byte is written and returns the number of bytes sent. On EOF recv(max) returns ok=True, value=""; real socket errors return ok=False with the strerror text. Use send_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 / TcpRecv wrapper classes (Result does 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 Authorization and Host, relative Location values merge per RFC 3986;
  • a keep-alive connection pool, automatic gzip/deflate decompression, trailer exposure, a cookie jar (Domain/Path/Secure/Max-Age), 1xx skipping, and no body for HEAD/204/304;
  • request-body compression (compress_request=True gzips the body and sends Content-Encoding: gzip);
  • HTTP proxies (absolute-form for plaintext, CONNECT tunnels for HTTPS with Proxy-Authorization);
  • client certificates via client_cert / client_key or set_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) and url_encode / url_decode;
  • async entry points http.get_async / post_async / request_async, which return Task[HttpResult] (one thread per task) and work with asyncio.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 (await is not yet wired to the event loop, see "Event loop"). Concurrent HTTP/2 multiplexing is available through http2.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 (handle field); it can only be created by calling an async function.
  • await / asyncio.gather consume tasks: a Task variable may be awaited only once; dropping an un-awaited task leaks its result box (reclaimed at process exit).
  • asyncio.gather takes a List[Task[T]] variable (consumed by the call) and returns Task[List[T]], which can be awaited or passed to asyncio.run; an empty list yields an empty list.
  • asyncio.wait_any takes a List[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 -1 for an empty list. It consumes neither the tasks nor the list, so they can still be awaited, cancelled or queried with another wait_any afterwards.
  • task.done() reads the completion flag atomically without blocking; after await the task variable has been consumed and can no longer be queried.
  • task.wait(ms) polls the completion flag: True when the task finishes, False on timeout (ms <= 0 checks 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 (False if already done or already requested); it does not kill the thread or consume the task. task.cancelled() reads the request flag and asyncio.cancelled() reads the current task's flag (False outside 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, str or custom classes; nested await, Task[int] annotations and List[Task[int]] all work.
  • Limits: no async def main, no async methods, no borrow parameters/returns; cancellation is cooperative; timeouts use wait polling; one thread per task, so the task count is bounded by the thread limit; List / Map writes are not synchronized across threads. An event loop is provided by the separate event module (see below), but it is not wired to await yet.

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 / remove manage registrations. Combine ev_in() / ev_out() / ev_err() / ev_hup() / ev_rdhup() / ev_edge() with |. wait(timeout_ms) returns up to 64 Event{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) and timer_count(); fired events carry ev_timeout().
  • Wakeups: loop.post(token) from the loop thread, event.post_fd(loop.wake_w, token) from another thread; wait returns ev_wake() plus the token.
  • Non-blocking IO: pair it with net.connect_start / connect_finish, TcpListener.try_accept, TcpStream.try_recv / try_send and udp.UdpSocket.try_recv_from / try_send_to; again=True means EAGAIN, distinguishing it from a real error.
  • Limits: Linux only; at most 64 events per wait; tokens are 0..2^62-1 and must be unique within a loop; control operations should run on the thread calling wait (post / post_fd are thread-safe).

Module overview​

Module / categoryContents
corebuilt-in types, basic operations, to_string, chr, format
ioinput/output, file read/write/append/exists/remove, printing
mathabs / min / max / sqrt / pow / floor / ceil
timenow_monotonic / now / sleep
randomseed / random_int / random_float
osexit / getenv / setenv / getcwd / system
jsonparse / stringify / builders / accessors / mutation
regexcompile / is_match / find / search / replace
bytesbinary buffers (bytes_new / bytes_from_str / push / get / slice / append ...) and binary-safe file I/O (read_bytes / write_bytes)
netTCP: 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
udpUDP: 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)
httpHTTP 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)
http2HTTP/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 / tlshttps 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)
cryptopure 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)
gzipgzip 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
tartar archives: list_entries / extract / create / builder (ustar, GNU LongLink, PAX; pair with gzip for .tar.gz)
asyncioasync: async def / await / asyncio.run / asyncio.gather / asyncio.wait_any / asyncio.cancelled / Task.done / Task.wait / Task.cancel, Task[T] (pthread)
eventevent loop: new_loop / add / modify / remove / wait / add_timer / add_interval / cancel_timer / post / post_fd / close (epoll + timerfd + socketpair)
stringtrim / find / replace / to_upper / to_lower / pad_left
listsum_ints / min_int / max_int / sort_ints / sort_strs / join_ints
pathpath checks / joining / directory and file names
error handlingResult[T, Err], ? propagation, match
sequencesrange(n) / range(start, end[, step])
utilitiesstring 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.