Rust → zust

Side-by-side comparison of common ownership patterns.
Coming from Rust? Here's how zust maps to what you know.

Heap Allocation
RUST
use std::boxed::Box;
fn main() {
    let b = Box::new(42);
    println!("{}", b);
} // dropped automatically
ZUST
const safe = @import("safe");
fn foo(allocator: std.mem.Allocator) !void {
    var b = try safe.Box(i32).init(allocator, 42);
    std.debug.print("{d}", .{b.ptr.*});
    _ = b.deinit(); // type error if forgotten
}
Growable Array
RUST
let mut vec = Vec::new();
vec.push(1);
vec.push(2);
let x = vec.pop(); // Option
ZUST
var list = safe.ArrayList(i32).init(allocator);
defer list.deinit(allocator);
try list.append(allocator, 1);
try list.append(allocator, 2);
const x = list.pop(); // i32 (panic if empty)
Hash Map
RUST
use std::collections::HashMap;
let mut map = HashMap::new();
map.insert("key", 42);
let val = map.get("key");
ZUST
var map = safe.HashMap(safe.String, i32).init(allocator);
defer map.deinit(allocator);
try map.put(allocator, "key", 42);
const val = map.get("key"); // ?i32
Shared Ownership
RUST
use std::sync::Arc;
let a = Arc::new(42);
let b = Arc::clone(&a);
println!("{}", Arc::strong_count(&a));
ZUST
var a = try safe.Arc(i32).init(allocator, 42);
defer a.deinit();
var b = a.clone();
std.debug.print("{d}", .{a.strong_count()});
Mutex
RUST
use std::sync::Mutex;
let m = Mutex::new(0);
{
    let mut guard = m.lock().unwrap();
    *guard += 1;
} // unlocked automatically
ZUST
var m = safe.Mutex(i32).init(0);
defer m.deinit();
{
    var guard = m.lock();
    guard.ptr.* += 1;
    guard.deinit(); // required in Zig
}
String
RUST
let mut s = String::new();
s.push_str("hello");
s.push_str(" world");
println!("{}", s);
ZUST
var s = safe.String.init(allocator);
defer s.deinit(allocator);
try s.appendSlice("hello");
try s.appendSlice(" world");
std.debug.print("{s}", .{s.slice()});
Optional / Null
RUST
let x: Option = Some(42);
let y = x.unwrap(); // panics if None
let z = x.unwrap_or(0);
ZUST
const x: ?i32 = 42;
const y = x.?; // compile error if null path untaken
const z = x orelse 0;
Iterator
RUST
let v = vec![1, 2, 3];
let doubled: Vec = v.iter()
    .map(|x| x * 2)
    .collect();
ZUST
var v = safe.ArrayList(i32).init(allocator);
// ... populate ...
var iter = safe.SliceIter(i32).init(v.slice());
var doubled = try iter.map(allocator, struct {
    fn f(x: i32) i32 { return x * 2; }
}.f);