rokdocs
v0.1

3. Std tier

The standard library of the target-dependent area. It covers the file system, networking, time, OS threads, I/O, environment variables, processes and paths, and availability varies with the user's environment (operating system / platform).

Location

The spec body lives under spec/en/refs-standard-libraries/300-std/.

Dependencies

Upward, it depends on rok and unsafe. Downward, user code stands in the dependent position, but std is pulled in only by an explicit import.

User import policy

The implicit use rok::core::**; does not include std items - rok::std::* requires a separate explicit import. Because availability differs by target, the design makes users express platform dependencies explicitly.

use rok::std::fs;
use rok::std::time::Instant;
use rok::std::thread::Builder;

Module index

This tier consists of the following ten modules.

Core design principles

1. Blocking API + *_async - no async traits

std I/O functions are sync and block the calling OS thread. To give up the worker while waiting inside a task, await the *_async method of the same operation (3.2.0). With stackless coroutines an ordinary function cannot suspend a task, so a sync call never becomes async on its own.

// blocking - on an OS thread (thread::spawn) or outside a task
fn fetch(addr: str) throws (IoError) -> List<u8> {
    using conn = try net::tcp_connect(addr) {
        try conn.read_to_end()
    }
}

// async - suspends only the task
async fn fetch_async(addr: str) throws (IoError) -> List<u8> {
    using conn = try await net::tcp_connect_async(addr) {
        try await conn.read_to_end_async()
    }
}

There are no AsyncRead / AsyncWrite traits. The async versions are inherent methods and functions of the types. Sockets wait for I/O driver readiness (3.2.0); regular files run the blocking call on another OS thread (3.1.4a).

2. I/O backend - runtime detail

Waiting for readiness is the runtime's responsibility (refs-lang 7.7). User code does not need to know which backend is running.

PlatformBackend
Linuxepoll (edge-triggered)
macOS / FreeBSDkqueue (EV_CLEAR)
WindowsIOCP
WASIwasi:io/poll (wasm32-wasi), poll_oneoff (wasm32-wasi-threads)

3. TLS 1.3 in std - HTTP out

TLS 1.3 is security-critical. If every application implemented TLS itself, security vulnerabilities would multiply, so it is integrated into std.

use rok::std::net::tls;

let conn = try net::tcp_connect("example.com:443");
let tls_conn = try tls::Client::new(conn, "example.com");
let req = b"GET / HTTP/1.1\r\nHost: example.com\r\n\r\n";
try tls_conn.write_all(req);
let resp = try tls_conn.read_to_end();

The stack is rok's own, written on rok::core::crypto (2.21); no OS or third-party TLS library is used (3.2.5).

HTTP/1, HTTP/2 and HTTP/3 (QUIC), on the other hand, live outside std, split into a separate rok/http package. This is the lesson from Go's net/http being frozen at 1.0.

4. Capability-based fs - Dir handles

Follows the pre-opened directory handle model of WASI Preview 2. Every fs op goes through a Dir.

use rok::std::fs::{Dir, File};

let root: Dir = Dir::root();                  // capability - at process start
let data_dir: Dir = try root.open_dir("data"); // sub-cap

let f: File = try data_dir.open("config.toml");
let bytes = try f.read_to_end();

The model has three advantages. First, it avoids TOCTOU - open after open_dir is race-free. Second, sandboxing comes naturally - pass only a narrow Dir to a child task. Third, it is WASI-compatible - the same code works on native and WASI.

For convenience, fs::open(absolute_path) is also allowed. Internally it expands to Dir::root().open(...).

5. UTF-8 Path (Python-style)

A decision to avoid the ergonomic burden of Rust's Path / PathBuf + OsStr.

use rok::std::path::Path;

let p: Path = Path::from("data/config.toml");
let parent: Path = p.parent()?;
let with_ext: Path = p.with_extension("bak");

// `/` operator (Python pathlib style)
let full = Path::from("/etc") / "nginx" / "nginx.conf";

Path is a UTF-8 newtype. Non-UTF-8 file names (which occasionally exist on Unix) are handled separately with RawPath (bytes). Path alone should cover 99% of code.

The detailed comparison and rationale are in 3.8 path.

6. All I/O throws (IoError)

Panics almost never occur (except OOM). File not found, permission denied and network failure are all thrown with a throws (IoError) signature and propagate by marking the call with try. There is no automatic conversion between error types; to turn one into another error type, wrap it in catch and rethrow.

fn load_config() throws (ConfigError) -> Config {
    let bytes = try fs::read("config.toml") catch e: IoError {
        throw ConfigError::Io(e);              // IoError → ConfigError (explicit conversion)
    };
    try parse(bytes)
}

Target availability

Module availability per platform:

Modulelinux/macos/windowswasm32-wasiwasm32-wasi-threadswasm32 (browser)
rok::std::fs✓✓ (cap-based)✓ (cap-based)✗ (every call Unsupported)
rok::std::net✓ (+ TLS 1.3)✓ (wasi:sockets)listeners passed in by the host✗ (use fetch)
rok::std::time✓✓✓✓ (Date.now)
rok::std::thread✓one thread (spawn Unsupported)✓ (wasi-threads)one thread (spawn Unsupported)
rok::std::io✓✓✓console / stdin at EOF
rok::std::env✓✓✓✗
rok::std::process✓✗✗✗
rok::std::path✓✓✓✓

✗ means the module builds but its operations fail at run time with IoErrorKind::Unsupported; it is not a compile-time absence. In the browser, stdout / stderr go to the host console and stdin is at EOF. The availability section of each module spec gives per-platform behavior in more detail.

Edit this page on GitHub