The standard library
std is an ordinary package: a directory of .volt files that voltc compiles along with your
program (--std DIR, $VOLT_STD, or the std/ next to voltc). The compiler knows only a few of
its names (@derive falls back to std::derive’s traits; bindings and C++ imports use std::vec
and std::string), so a std of your own can replace it as long as it keeps those.
Each file is wrapped in namespace std, and most declare a namespace of their own inside it. The
parts that need an OS (files, processes, time, random bytes, networking and threads) have code for
Linux, macOS, FreeBSD and Windows, 64-bit, on x86-64 and ARM64, picked with
@cfg:
| Module | What it has |
|---|---|
std::io |
println, print, eprintln, eprint: formatted output, checked at compile time (Printing) |
std::fmt |
format (text as a std::string) and write (into any writer); format specifiers like {:>8.2} (Formatting into strings and writers) |
std::text |
methods on str: search, trim, split, replace, case, parse numbers; UTF-8; ASCII classes on u8; join (Text and strings) |
std::string |
string: owned, growable UTF-8 text (Building text) |
std::vec |
vec<T>: a growable array that owns its elements; insert, remove, retain, dedup |
std::map |
map<K, V>: a hash map, iter() over its entries, and hash for the built-in key types |
std::set |
set<T>: a hash set |
std::sorted_map |
sorted_map<K, V>: a map that walks its keys in order |
std::deque |
deque<T>: a double-ended queue |
std::heap |
heap<T>: a priority queue, smallest first |
std::slice |
on any T[..]: stable sort, sort_by, binary_search, reverse, contains, min, max (Collections and algorithms) |
std::compare |
eq and cmp, which collections and algorithms compare values with (Comparing values) |
std::derive |
what @derive(eq, hash, fmt, json) attaches (Derive) |
std::math |
constants, sqrt, pow, trig and the rest of libm (f64 and f32; in Volt as std::math::portable), min/max/clamp, integer limits, checked and saturating arithmetic, gcd/lcm (Math) |
std::simd |
SIMD vectors (f64x2, f32x4, i32x4, …, or vec(T, n)): arithmetic lane by lane, lanes by index, splat, sum, load, store (SIMD vectors) |
std::random |
random numbers (xoshiro256**), seeded or from the OS; ranges, floats, shuffle, choose; secure OS bytes (Random numbers) |
std::mem |
the allocator trait and allocators (arena, fixed_buffer, failing), box<T> (an owning pointer), T::new, mem_error (Allocators) |
std::fs |
files and directories: whole files, file streams (open, read_line, seek), listing, walking, creating, removing (Files) |
std::path |
paths as text: join, parent, file_name, extension, normalize (Paths) |
std::process |
running programs, arguments, the environment and the working directory, exit (Processes) |
std::time |
the monotonic clock, the wall clock, sleep, durations, UTC dates in ISO 8601 (Time) |
std::net |
TCP (listen, connect, streams), UDP, resolve, timeouts; the same on Linux, macOS, FreeBSD and Windows (Networking) |
std::thread |
threads (spawn, join), mutex<T> and its guard, cond, atomic_i64/atomic_bool, shared<T>, channel<T> (Threads) |
std::json |
JSON values: parse, build and print (JSON) |
std::html |
text escaped for HTML, and templates (slots, loops, conditions) rendered from JSON values or checked against a type while compiling (HTML templates) |
std::base64, std::hex |
bytes as base64 (standard and URL-safe) or hex text, and back (Encoding and hashing) |
std::digest |
CRC-32, 64-bit FNV-1a and SHA-256 (in one call, or fed in pieces) (Checksums and hashes) |
std::softfloat |
IEEE 754 arithmetic, comparison and conversion on the bits of f32s and f64s with integer instructions only: what bare metal cores without a floating-point unit use |
std::softint |
division, 64-bit shifts and wide multiplies from 32-bit operations, for cores without them (a Cortex-M0); std/bare.volt hands them and the rest of a bare-metal program’s runtime to the compiler, in place of C’s |
std::testing |
assertions that print the values they compared (assert_eq, assert_near, …), and run for a file of tests (Tests) |
Reaching the names
Section titled “Reaching the names”use std::io; makes std::io’s members reachable through the first namespace, so
std::io::println can be written std::println. The containers are declared directly in std
(std::string, std::vec<T>, std::map<K, V>; see Collections),
and box in std::mem.
use std::io;
fn main() -> !void { var names: std::vec<std::string> = {}; try names.push(std::string::from("volt")); var ages: std::map<str, i32> = {}; ages.put("volt", 1); val b: std::mem::box<i32> = try i32::new(5); std::println("{} {} {} {}", names.len, names[0], *(ages.get("volt") ?? return), b);}// expect: 1 volt 1 5Your own std
Section titled “Your own std”A std binds what only the compiler can do through two attributes:
@attributes([@intrinsic("println")])on a body-lessfnmakes it a compiler builtin (the formatted print functions,formatandwrite) or, for a name starting withvolt_, a function of the C runtime. The runtime’s functions include allocation, atomics, and threads with a wait and wake on a word, so another std can build threads too.@attributes([@owns("ptr")])on a struct makes it an owning pointer likebox: it’s used like aT&, and when it goes out of scope the value it points at is deleted first.
tests/std_alt in the repository is a std written from scratch. In bolt, [std] path = "../mystd"
picks one per package; voltc --std DIR does it by hand.
Documentation from source
Section titled “Documentation from source”The reference pages (std::io and the rest) come from voltc doc std, which prints a package’s declarations and their comments as
JSON (the comment block directly above a declaration, or after a field on its line). Run it on your
own packages with voltc doc NAME --pkg NAME=DIR.