Skip to main content

Standard Library

Built-in types: string, Vec, HashMap, Iterator, IO.

Built-ins and modules

Primitive types, Option, Result, strings, collections and Rc/Weak are available directly. Import standard modules for filesystem, networking, time, encoding and process operations. Native execution provides the host services; the browser sandbox reports capabilities that require native execution.

string

string is an owned UTF-8 value. Operations preserve value semantics; programmers do not manage its backing allocation.

string
// Built-in methods on string values:
//   s.len() -> i64
//   s.split(sep) -> Vec<string>      s.trim() -> string
//   s.starts_with(p) -> bool         s.ends_with(p) -> bool
//   s.contains(sub) -> bool          s[a..b] -> string (half-open)
//   s.find(sub) -> Option<i64>       (None when not found)
//   s.get(i) -> Option<char>         s.to_upper() -> string
 
// std.string adds conversions and padding:
import std.string;
 
fn main() {
    let n = "42".to_int().expect("valid integer"); // i64
    let s = f"{42}";                             // "42"
    let padded = "7".pad_left(3, '0');            // "007"
    let joined = ["a", "b", "c"].join(", ");
    _ = (n, s, padded, joined);
}

Vec<T>

Vec<T> is a growable, heap-allocated array. It manages a contiguous block of memory with a length and capacity.

Vec<T>
// Vec<T> methods:
//   Vec.new() -> Vec<T>
//   v.push(item: T)            v.pop() -> T   (traps if empty)
//   v.len() -> i64             v.get(i) -> Option<T>
//   v.clone() -> Vec<T>
//
// .get(i) is bounds-checked and returns Option<T>; match before using it.
 
fn main() {
    var items: Vec<i64> = Vec.new();
    items.push(10);
    items.push(20);
    println(items.len());   // 2
    match items.get(0) {
        .Some(value) => println(value),  // 10
        .None => println("missing"),
    }
}

HashMap<K, V>

HashMap<K, V> is a hash table using Robin Hood hashing. Keys must implement Hash + Eq.

HashMap<K, V>
// HashMap<K, V> methods:
//   HashMap.new() -> HashMap<K, V>
//   m.insert(key: K, value: V)        // returns unit; overwrites on duplicate
//   m.get(key: K) -> Option<V>        // match the Some/None arms
//   m.remove(key: K) -> bool
//   m.contains_key(key: K) -> bool
//   m.len() -> i64
 
fn main() {
    var m: HashMap<string, i64> = HashMap.new();
    m.insert("alice", 10);
    match m.get("alice") {
        .Some(v) => println(v),       // 10
        .None => println("missing"),
    }
}

Iterator

The Iterator trait provides lazy, composable data transformation with combinators like map, filter, fold, and collect.

Lazy iterator adapters
import std.iter;
 
fn main() {
    var numbers: Vec<i64> = Vec.new();
    numbers.push(1);
    numbers.push(2);
    numbers.push(3);
    numbers.push(4);
 
    let even = iter.filter(numbers.into_iter(), |n: i64| n % 2 == 0);
    let doubled = iter.map(even, |n: i64| n * 2);
    let result: Vec<i64> = iter.collect(doubled);
    println(result.len()); // 2
}

IO

std.io reads standard input and writes standard output or standard error. A read waits cooperatively, so other tasks can keep running while input is quiet. Operations use Hew's explicit fails path; read_line returns None at end of input.

Standard input and output
import std.io;
 
fn main() fails io.IoError {
    io.write("Name: ")?;
    let name = io.read_line()? ?? "stranger";
    io.write(f"Hello, {name}\n")?;
}

File I/O

The std.fs module provides convenience functions for reading, writing, and deleting files. The std.stream module adds streaming file access via stream.open(path) — iterate byte chunks with for for line-by-line processing without loading the entire file into memory.

Hew v0.9.3 provides fs.ReadFile and fs.WriteFile capabilities for directional access to an individual opened file. Create them with fs.open_read or fs.open_write. See file capabilities and confinement for a complete example.

File I/O
import std.fs;
import std.stream;
import std.encoding.utf8;
import std.os;
 
fn main() {
    let tmp = os.temp_dir();
    let path = tmp + "/example.txt";
 
    // Write and read a file
    fs.write(path, "apple\nbanana\ncherry\n").expect("write example file");
    let content = fs.read(path).expect("read example file");
    println(content);
    let size = fs.size(path).expect("read example file size");
    println(f"Size: {size} bytes");
 
    // Stream: consume byte chunks from a file
    let src = match stream.open(path) {
        .Ok(s) => s,
        .Err(e) => { panic(e); }
    };
    for chunk in src {
        print(utf8.decode_lossy(chunk));
    }
 
    // Cleanup
    fs.delete(path).expect("delete example file");
}

CLI arguments

The std.os module provides access to command-line arguments. Use os.args() to get a vector of arguments, including the executable name at index zero. String methods like starts_with and find, together with range slices, handle parsing.

CLI argument parsing
import std.os;
 
fn main() {
    let args = os.args();
    let argc = args.len();
    if argc <= 1 {
        println("Usage: myapp [OPTIONS] [FILES...]");
        return;
    }
 
    var i = 1;
    while i < argc {
        let arg = args[i];
        if arg.starts_with("--") {
            match arg.find("=") {
                .Some(eq_pos) => {
                    let key = arg[2..eq_pos];
                    let val = arg[eq_pos + 1..];
                    println(f"{key} = {val}");
                }
                .None => println(f"flag: {arg}"),
            }
        } else {
            println(f"file: {arg}");
        }
        i += 1;
    }
}

Stream channels

std.stream.pipe(capacity) creates a bounded, typed channel for passing data between producers and consumers. The producer writes to the sink; the consumer reads with for. Close the sink to signal completion. The for loop consumes the stream, so there is no close call on the consumer side.

Stream channels
import std.stream;
 
fn main() {
    let (sink, input) = stream.pipe<string>(8).expect("create pipe");
 
    // Producer writes to sink
    sink.send("alpha").expect("reader closed");
    sink.send("beta").expect("reader closed");
    sink.send("gamma").expect("reader closed");
    sink.send("delta").expect("reader closed");
    sink.close();
 
    // Iteration consumes the stream and drains it to EOF
    for item in input {
        println(item);
    }
}

Resource lifetimes

Ordinary values and standard resource handles are cleaned up automatically. Use #[resource] with fn close(consume self) for an owned native resource, and keep unsafe pointer operations at explicit foreign-function boundaries. See ownership and deterministic cleanup for the language rules and Ownership and Affine Values for a task-oriented explanation.