The Standard Library
std is written entirely in Cryo and ships with the compiler as a static library plus its sources. Nothing in it is privileged: the same type struct, type trait, and implement declarations available to your code build Array<T>, HashMap<K, V>, and the HTTP server. When a signature here looks like something you could have written, that is because it is.
The library is layered. core sits at the bottom and neither allocates nor performs I/O — it is the vocabulary the language itself is defined against. alloc introduces the heap, collections builds growable containers on top of it, and everything above that is domain-specific: files, sockets, threads, formatting, time.
core language foundations - no heap, no I/O
|
alloc Layout, Allocator, Box, Rc, Arc, Arena, Pool
|
collections Array, Str, String, HashMap, HashSet, Pair
|
io fmt fs net sync thread future process time json ...
The prelude
A small set of names is imported into every source file automatically. The set is deliberately short — each entry competes for your attention — and most of it is there because the language desugars to it.
| Module | What it brings in |
|---|---|
core::panic | panic(message, file, line) -> never, plus assert, unreachable, and todo |
core::option | Option<T> and its methods |
core::result | Result<T, E> and its methods |
core::primitives | Methods on the built-in types (i32::max_value, char::is_digit, ...) |
core::intrinsics | Compiler intrinsics: memcpy, memset, sizeof, alignof, malloc, free |
core::varargs | VaArgs, the compiler-assigned type of a function's args... bucket |
collections::array | Array<T>, because T[] desugars to it |
core::slice | Slice<T>, which backs for (x in arr) over a fixed-size array |
core::ops | Range and RangeInclusive, because a..b desugars to Range::new |
core::iter | Iterator, the trait for-in drives its scrutinee through |
alloc::box | Box<T> |
alloc::rc | Rc<T> |
Everything else is an explicit import. Most notably the print / println / eprint / eprintln family lives in fmt and is not in the prelude:
namespace app;
import std::fmt::display;
function main() -> i32 {
println("hello");
return 0;
}
Importing
Standard library paths are rooted at std, and you import the module that owns the item you want:
import std::collections::array; // the module
import std::collections::{ str, string }; // two modules from one parent
import std::net::http::status as http_status;
import std::fmt::display::*; // everything public in the module
Each module page below records the exact import path for the types it documents. Importing a parent aggregator (import std::collections;) brings in whatever that directory's _module.cryo marks public. See Modules and Imports for the full rules.
Module directory
| Module | What it covers |
|---|---|
core | Option, Result, Slice, NonNull, Range, Ordering, and the trait vocabulary the language is defined against |
alloc | Layout, the Allocator trait, Box, Rc, Arc, Arena, Pool |
collections | Array, Str, String, HashMap, HashSet, Pair |
fmt | Display, Debug, Formatter, the print family, heap-free number writers |
json | RFC 8259 value model, parser, and serializer |
encoding | Base64 and SHA-1 |
io | Read / Write, the standard streams, buffered adapters, IoError |
fs | Path, PathBuf, File, directories, metadata |
env | Arguments, environment variables, process exit |
process | Command, Child, Stdio, ExitStatus, signals |
time | Duration, Instant, SystemTime, sleep |
ffi | The C ABI boundary: libc, CStr, CString |
sys | Raw syscalls, and the Win32 / NT surfaces |
math | libm wrappers, width-generic where it makes sense |
random | Rng (xoshiro256**) and SecureRng |
sync | Atomic, Mutex, RwLock, CondVar, Once, Barrier, mpsc channels |
thread | spawn, JoinHandle, Builder, scoped threads, thread-local storage |
future | Future, Poll, Context, Waker, combinators, block_on |
net | IP addressing, DNS, TCP, UDP, TLS |
net::http | HTTP/1.1 client and server, HTTP/2, WebSocket |
test | The built-in unit-test framework |
Conventions
The standard library follows a handful of rules consistently. User code is encouraged to mirror them, and knowing them up front means you can predict most signatures before reading them.
Result for expected failure, panic for broken invariants. A function returns Result<T, E> whenever failure is part of its contract — a file that might not exist, a parse that might not succeed. It panics only when the contract cannot be preserved at all, such as an out-of-bounds index on a method whose contract excludes it. Fallible constructors are usually spelled try_* next to a panicking sibling.
No NUL-terminated strings outside ffi. Every other module works in length-typed Str and String values. Translation to and from C strings happens at the boundary, in ffi.
Explicit resource management. Every owning type exposes drop(mut &this), and its documentation says who is responsible for calling it. In practice the compiler synthesises drops at scope exit — see Ownership, Copy, and Drop — and a manual .drop() remains available for early release.
Allocator-generic containers. Array<T, A>, HashMap<K, V, A>, String<A>, Box<T, A>, Rc<T, A>, and PathBuf<A> all take the allocator as a trailing type parameter defaulting to GlobalAlloc. The *_in constructors plug in an arena, a pool, or your own strategy without changing any other code.
No magic numbers. Every numeric constant in the library is named. A bare literal in a signature is a bug report waiting to happen.
Reading the sources
Each page here documents the surface, but the library is short and readable, and its doc comments are the ground truth. The manifest at stdlib/lib.cryo lists every module, and each directory's _module.cryo describes what its files contain.