std — core library #
The std namespace is built into every RinneScript program — no import
required. You may still write @import = .{ std }; for clarity, but it is
not necessary.
Other modules (c, ai, llm, net) must be explicitly imported:
@import = .{ c, ai, llm, net };
Unknown modules fail at compile time:
compile error: unknown module 'http' in @import (known modules: std, ai)
Printing #
std.print / std.stdout write to stdout; std.stderr and std.log to
stderr. All of them take a format string plus a tuple — the tuple form is
required:
std.print("x={}\n", .{42});
std.print("{} + {} = {}\n", .{1, 2, 3});
std.stderr("warn: {}\n", .{"disk almost full"});
{} is a placeholder; {{ and }} are literal braces.
Casting with @as #
@as(type, value) converts values explicitly:
| Type name | Meaning |
|---|---|
int, i32, i64, u8, u32, u64, usize |
integer conversion |
float, f32, f64 |
floating-point conversion |
str, string |
render value as text |
bool |
truthiness |
const f = @as(float, 7); // 7.0
const i = @as(int, 3.9); // 3 (truncates)
const s = @as(str, 42); // "42"
const b = @as(bool, 0); // false
An unknown type name fails at runtime:
unknown type 'complex' in @as.
Strings — std.strings #
All string builtins take and return immutable strings unless noted.
| Builtin | Description |
|---|---|
len(s) |
length of string, array, or vector |
slice(s, start, end) |
substring (negative indices count from the end) |
split(s, sep), join(parts, sep) |
split on separator / join with separator |
trim(s) |
strip leading/trailing whitespace |
replace(s, from, to) |
replace all occurrences |
contains(s, sub), starts_with(s, p), ends_with(s, p) |
substrings tests |
to_lower(s), to_upper(s) |
case conversion |
repeat(s, n) |
concatenate s n times |
chars(s) |
array of single-character strings |
reverse(s) |
reversed string |
std.print("{} — {}\n", .{
std.strings.repeat("ab", 3), // ababab
std.strings.reverse("hello"), // olleh
});
std.print("{}\n", .{std.strings.chars("hi")}); // ["h", "i"]
Math — std.math #
Numeric helpers that keep integers as integers and widen to floats when the input is a float.
| Builtin | Description |
|---|---|
abs(x) |
absolute value (int stays int) |
floor(x), ceil(x), round(x) |
rounding (result is a float) |
sqrt(x) |
square root (float) |
pow(x, y) |
x raised to y (float) |
min(a, b), max(a, b) |
extremum, ints stay ints |
clamp(x, lo, hi) |
clamp x into [lo, hi] (int stays int) |
std.print("{}\n", .{std.math.abs(-7)}); // 7
std.print("{}\n", .{std.math.floor(2.7)}); // 2
std.print("{}\n", .{std.math.sqrt(81)}); // 9
std.print("{}\n", .{std.math.clamp(15, 1, 10)}); // 10
File I/O — std.io #
std.io.stdout is a callable form of the @stdout directive. The file
helpers operate on absolute or cwd-relative paths; parents of a target file
must exist (make_dir_all creates an entire tree).
| Builtin | Description |
|---|---|
read_file(path) |
contents as a string |
write_file(path, data) |
write (truncating), true on success |
append_file(path, data) |
append, true on success |
file_exists(path) |
boolean |
make_dir(path) |
create one directory, true if created |
make_dir_all(path) |
create directory and any missing parents |
remove_file(path) |
delete a file |
remove_dir(path) |
delete an empty directory |
rename_file(from, to) |
move a file, true on success |
list_dir(path) |
array of entry names |
std.io.make_dir_all("/tmp/rg_demo/sub");
std.io.write_file("/tmp/rg_demo/f.txt", "line1\n");
std.io.append_file("/tmp/rg_demo/f.txt", "line2\n");
std.print("{}", .{std.io.read_file("/tmp/rg_demo/f.txt")});
std.print("{}\n", .{std.io.list_dir("/tmp/rg_demo")});
JSON and data formats — std.json #
json_parse turns a JSON string into a value (map/array/scalar); the
json_stringify and json_pretty functions serialize back. Map iteration
order is unspecified, so treat serialized maps as unordered.
| Builtin | Description |
|---|---|
json_parse(text) |
parse a JSON document |
json_stringify(v) |
compact single-line JSON |
json_pretty(v) |
indented, human-readable JSON |
csv_parse(text), csv_format(rows) |
CSV text <-> array of arrays |
base64_encode(data), base64_decode(text) |
base64 round trip |
const doc = std.json.json_parse("{\"name\": \"rinne\"}");
std.print("{}\n", .{doc["name"]}); // rinne
std.print("{}\n", .{std.json.json_pretty(doc)});
// {
// "name": "rinne"
// }
Collections — std.collections #
Arrays are values, so "mutating" helpers return a new array.
| Builtin | Description |
|---|---|
push(arr, v) |
new array with v appended |
map_new(k0, v0, ...) |
build a string-keyed map from pairs |
contains_val(coll, v) |
does the array hold v, or the map contain it as a value? |
const xs = std.collections.push([1, 2], 3);
std.print("{}\n", .{std.collections.contains_val(xs, 3)}); // true
std.print("{}\n", .{std.collections.contains_val({"a": 1}, 1)}); // true
Type aliases (std/types.rg) #
std/types.rg documents the canonical aliases used across the standard
library and examples (vec16f, byte, ...). The VM is dynamically typed, so
annotations are documentation sugar — they parse today and read well, but do
not change runtime behavior.
Runnable example #
pub fn main() int {
const x = @int(3.9);
const f = @as(float, 7);
std.print("@int(3.9)={} @as(float,7)={} str(42)='{}'\n", .{x, f, @as(str, 42)});
return 0;
}
Output:
@int(3.9)=3 @as(float,7)=7 str(42)='42'
Module gating #
std is implicitly imported — all std.* builtins are available immediately.
Modules c, ai, llm, and net require an explicit import at the top of
the file:
@import = .{ c, ai, llm, net };
Without the import, calling c.load_lib, ai.load_safetensors,
ai.load_gguf, llm.llm_load, net.tcp_listen, or net.tcp_connect
fails at compile time.