donna_stdlib — API Reference

The Donna standard library

time

Monotonic clock utilities.

The values come from the platform monotonic clock, so they are useful for measuring elapsed time. They are not wall-clock timestamps.

Functions

pub fn now_ms() -> Int

Return the current monotonic clock value in milliseconds.

time.now_ms()
pub fn now_us() -> Int

Return the current monotonic clock value in microseconds.

time.now_us()

dict

Generic association list dictionary.

Keys are compared using a caller-supplied equality function: for Int keys: fn(a: Int, b: Int) -> a == b for String keys: fn(a: String, b: String) -> string.equal(a, b)

All operations are O(n), suitable for small-to-medium maps.

Types

pub type Dict(k, v)

An association list: each entry stores a key, value, and pointer to the rest.

Empty
Entry(k, v, Dict(k, v))

Functions

pub fn new() -> Dict(k, v)

Create an empty dictionary.

dict.new()
pub fn insert(d: Dict(k, v), key: k, val: v, eq: fn(k, k) -> Bool) -> Dict(k, v)

Insert or update a key. If the key already exists (per eq), its value is replaced.

dict.insert(dict.new(), "name", "Donna", fn(a: String, b: String) -> string.equal(a, b))
pub fn get(d: Dict(k, v), key: k, default: v, eq: fn(k, k) -> Bool) -> v

Look up a key, returning the value or a default if not found.

dict.get(users, "name", "missing", fn(a: String, b: String) -> string.equal(a, b))
pub fn has_key(d: Dict(k, v), key: k, eq: fn(k, k) -> Bool) -> Bool

Return True if the key is present.

dict.has_key(users, "name", fn(a: String, b: String) -> string.equal(a, b))
pub fn delete(d: Dict(k, v), key: k, eq: fn(k, k) -> Bool) -> Dict(k, v)

Remove a key from the dictionary. No-op if not present.

dict.delete(users, "name", fn(a: String, b: String) -> string.equal(a, b))
pub fn size(d: Dict(k, v)) -> Int

Return the number of entries.

dict.size(users)
pub fn is_empty(d: Dict(k, v)) -> Bool

Return True if the dictionary has no entries.

dict.is_empty(dict.new())
pub fn keys(d: Dict(k, v)) -> List(k)

Return all keys as a list (insertion order reversed).

dict.keys(users)
pub fn values(d: Dict(k, v)) -> List(v)

Return all values as a list (insertion order reversed).

dict.values(users)
pub fn to_list(d: Dict(k, v)) -> List(#(k, v))

Convert to a list of key-value pairs.

dict.to_list(users)
pub fn from_list(pairs: List(#(k, v)), eq: fn(k, k) -> Bool) -> Dict(k, v)

Build a dictionary from a list of key-value pairs. Later entries in the list take precedence over earlier ones for the same key.

dict.from_list([#("name", "Donna")], fn(a: String, b: String) -> string.equal(a, b))
pub fn merge(base: Dict(k, v), other: Dict(k, v), eq: fn(k, k) -> Bool) -> Dict(k, v)

Merge two dicts: entries in other override entries in base for duplicate keys.

dict.merge(base, overrides, fn(a: String, b: String) -> string.equal(a, b))
pub fn map_values(d: Dict(k, v), f: fn(v) -> b) -> Dict(k, b)

Apply a function to every value, returning a new dict with the same keys.

dict.map_values(scores, fn(n: Int) -> n + 1)
pub fn filter(d: Dict(k, v), f: fn(k, v) -> Bool) -> Dict(k, v)

Keep only entries where f(key, value) returns True.

dict.filter(scores, fn(k: String, v: Int) -> v > 0)
pub fn fold(d: Dict(k, v), init: b, f: fn(b, k, v) -> b) -> b

Fold over all entries, accumulating a result.

dict.fold(scores, 0, fn(acc: Int, k: String, v: Int) -> acc + v)
pub fn find_keys(d: Dict(k, v), f: fn(k, v) -> Bool) -> List(k)

Return all keys satisfying a predicate.

dict.find_keys(scores, fn(k: String, v: Int) -> v > 0)
pub fn update(d: Dict(k, v), key: k, f: fn(v) -> v, eq: fn(k, k) -> Bool) -> Dict(k, v)

Update a key with a function. No-op if the key is not present.

dict.update(scores, "total", fn(n: Int) -> n + 1, fn(a: String, b: String) -> string.equal(a, b))

result

Result type and utilities for Donna.

Types

pub type Result(a, e)

The Result type represents either success (Ok) or failure (Error).

Ok(a)
Error(e)

Functions

pub fn is_ok(res: Result(a, e)) -> Bool

Return True if the result is Ok.

result.is_ok(result.Ok(42))
pub fn is_error(res: Result(a, e)) -> Bool

Return True if the result is an Error.

result.is_error(result.Error("no"))
pub fn unwrap(res: Result(a, e), default: a) -> a

Unwrap the Ok value, returning default if Error.

result.unwrap(result.Ok(42), 0)
pub fn unwrap_error(res: Result(a, e), default: e) -> e

Unwrap the Error value, returning default if Ok.

result.unwrap_error(result.Error("no"), "")
pub fn map(res: Result(a, e), f: fn(a) -> b) -> Result(b, e)

Apply f to the Ok value, leaving Error unchanged.

result.map(result.Ok(2), fn(n: Int) -> n * 2)
pub fn map_error(res: Result(a, e), f: fn(e) -> f) -> Result(a, f)

Apply f to the Error value, leaving Ok unchanged.

result.map_error(result.Error("no"), fn(e: String) -> "error: " <> e)
pub fn then(res: Result(a, e), f: fn(a) -> Result(b, e)) -> Result(b, e)

Chain: apply f which returns a Result, flattening the result.

result.then(result.Ok(2), fn(n: Int) -> result.Ok(n * 2))
pub fn or(res: Result(a, e), fallback: Result(a, e)) -> Result(a, e)

Return first Ok, or the second result if the first is an Error.

result.or(result.Error("no"), result.Ok(42))
pub fn to_list(res: Result(a, e)) -> List(a)

Convert Result to a list: Ok(x) -> [x], Error(_) -> [].

result.to_list(result.Ok(42))

files

File system utilities.

Functions

pub fn read(path: String) -> String

Read the entire contents of a file. Returns "" if the file does not exist.

files.read("README.md")
pub fn write(path: String, content: String) -> Int

Write content to a file, overwriting any existing content. Returns 0 on success, non-zero on error.

files.write("out.txt", "hello")
pub fn append(path: String, content: String) -> Int

Append content to a file. Returns 0 on success, non-zero on error.

files.append("out.txt", "\nagain")
pub fn exists(path: String) -> Bool

Return True if the path exists (file or directory).

files.exists("out.txt")
pub fn is_file(path: String) -> Bool

Return True if the path is a regular file.

files.is_file("out.txt")
pub fn is_dir(path: String) -> Bool

Return True if the path is a directory.

files.is_dir("src")
pub fn mkdir(path: String) -> Int

Create a directory. Returns 0 on success, non-zero on error.

files.mkdir("tmp")
pub fn delete(path: String) -> Int

Delete a file. Returns 0 on success, non-zero on error.

files.delete("out.txt")
pub fn copy(src: String, dst: String) -> Int

Copy a file from src to dst. Returns 0 on success, non-zero on error.

files.copy("in.txt", "out.txt")
pub fn list_dir(path: String) -> List(String)

List the entries in a directory. Returns a list of entry names (not full paths).

files.list_dir("src")
pub fn join(a: String, b: String) -> String

Join two path segments with a "/" separator.

files.join("src", "main.donna")
pub fn basename(path: String) -> String

Return the final component of a path (the filename).

files.basename("src/main.donna")
pub fn dirname(path: String) -> String

Return the directory component of a path (everything before the last "/"). Returns "." if there is no directory component.

files.dirname("src/main.donna")
pub fn extension(path: String) -> String

Return the file extension including the dot (e.g. ".donna"), or "" if none.

files.extension("src/main.donna")
pub fn drop_extension(path: String) -> String

Return the path with the extension removed.

files.drop_extension("src/main.donna")

option

Option type and utilities for Donna.

Types

pub type Option(a)

The Option type represents a value that may or may not be present.

None
Some(a)

Functions

pub fn is_some(opt: Option(a)) -> Bool

Return True if the option contains a value.

option.is_some(option.Some(42))
pub fn is_none(opt: Option(a)) -> Bool

Return True if the option is empty.

option.is_none(option.None)
pub fn unwrap(opt: Option(a), default: a) -> a

Unwrap the value, returning default if None.

option.unwrap(option.Some(42), 0)
pub fn map(opt: Option(a), f: fn(a) -> b) -> Option(b)

Apply f to the contained value, or return None.

option.map(option.Some(2), fn(n: Int) -> n * 2)
pub fn then(opt: Option(a), f: fn(a) -> Option(b)) -> Option(b)

Apply f which itself returns an Option, flattening the result.

option.then(option.Some(2), fn(n: Int) -> option.Some(n * 2))
pub fn or(opt: Option(a), fallback: Option(a)) -> Option(a)

Return the first option if it has a value, otherwise return the second.

option.or(option.None, option.Some(42))
pub fn lazy_unwrap(opt: Option(a), f: fn() -> a) -> a

Return the value if Some, or call f to produce a default.

option.lazy_unwrap(option.None, fn() -> 42)
pub fn filter(opt: Option(a), f: fn(a) -> Bool) -> Option(a)

Filter: return None if the predicate fails.

option.filter(option.Some(4), fn(n: Int) -> n > 0)
pub fn to_list(opt: Option(a)) -> List(a)

Convert Option to a list of 0 or 1 elements.

option.to_list(option.Some(42))

bool

Boolean utilities for Donna.

Functions

pub fn not(b: Bool) -> Bool

Negate a boolean value.

bool.not(False)
pub fn and(a: Bool, b: Bool) -> Bool

Logical AND.

bool.and(True, False)
pub fn or(a: Bool, b: Bool) -> Bool

Logical OR.

bool.or(True, False)
pub fn xor(a: Bool, b: Bool) -> Bool

Logical XOR (exclusive or).

bool.xor(True, False)
pub fn to_int(b: Bool) -> Int

Convert a bool to an integer: True -> 1, False -> 0.

bool.to_int(True)
pub fn to_string(b: Bool) -> String

Convert a bool to a string.

bool.to_string(False)
pub fn guard(b: Bool, then_val: a, else_val: a) -> a

Return a value based on a boolean condition.

bool.guard(True, "yes", "no")

float

Float utilities for Donna.

External functions

@external pub fn to_string(f: Float) -> String

Convert a float to its string representation.

float.to_string(3.14)
@external pub fn parse(s: String) -> Float

Parse a float string. Invalid strings currently parse as 0.

float.parse("3.14")
@external pub fn min(a: Float, b: Float) -> Float

Return the smaller of two floats.

float.min(1.0, 2.0)
@external pub fn max(a: Float, b: Float) -> Float

Return the larger of two floats.

float.max(1.0, 2.0)
@external pub fn clamp(x: Float, lo: Float, hi: Float) -> Float

Clamp a float between lower and upper bounds.

float.clamp(12.0, 0.0, 10.0)
@external pub fn is_positive(x: Float) -> Bool

Return True when the float is greater than zero.

float.is_positive(1.0)
@external pub fn is_negative(x: Float) -> Bool

Return True when the float is less than zero.

float.is_negative(-1.0)
@external pub fn is_zero(x: Float) -> Bool

Return True when the float is exactly zero.

float.is_zero(0.0)
@external pub fn sqrt(x: Float) -> Float

Return the square root.

float.sqrt(9.0)
@external pub fn abs(x: Float) -> Float

Return the absolute value.

float.abs(-3.0)
@external pub fn floor(x: Float) -> Float

Round downward to the nearest integer-valued float.

float.floor(3.8)
@external pub fn ceil(x: Float) -> Float

Round upward to the nearest integer-valued float.

float.ceil(3.2)
@external pub fn round(x: Float) -> Float

Round to the nearest integer-valued float.

float.round(3.5)
@external pub fn pow(base: Float, exp: Float) -> Float

Raise a base to an exponent.

float.pow(2.0, 8.0)
@external pub fn sin(x: Float) -> Float

Return the sine of a value in radians.

float.sin(0.0)
@external pub fn cos(x: Float) -> Float

Return the cosine of a value in radians.

float.cos(0.0)
@external pub fn tan(x: Float) -> Float

Return the tangent of a value in radians.

float.tan(0.0)
@external pub fn log(x: Float) -> Float

Return the natural logarithm.

float.log(10.0)
@external pub fn log2(x: Float) -> Float

Return the base-2 logarithm.

float.log2(8.0)
@external pub fn log10(x: Float) -> Float

Return the base-10 logarithm.

float.log10(100.0)
@external pub fn exp(x: Float) -> Float

Return e raised to the given power.

float.exp(1.0)

int

Integer utilities for Donna.

Functions

pub fn parse(s: String) -> option.Option(Int)

Parse a decimal integer string. Returns Some(n) on success. Note: uses atoi — always returns Some; invalid strings give 0.

int.parse("42")
pub fn to_string(n: Int) -> String

Convert an integer to its string representation.

int.to_string(42)
pub fn abs(n: Int) -> Int

Return the absolute value of an integer.

int.abs(-5)
pub fn min(a: Int, b: Int) -> Int

Return the minimum of two integers.

int.min(3, 7)
pub fn max(a: Int, b: Int) -> Int

Return the maximum of two integers.

int.max(3, 7)
pub fn clamp(n: Int, lo: Int, hi: Int) -> Int

Clamp a value between lo and hi (inclusive).

int.clamp(12, 0, 10)
pub fn is_even(n: Int) -> Bool

Check if an integer is even.

int.is_even(4)
pub fn is_odd(n: Int) -> Bool

Check if an integer is odd.

int.is_odd(3)
pub fn is_zero(n: Int) -> Bool

Check if an integer is zero.

int.is_zero(0)
pub fn is_positive(n: Int) -> Bool

Check if an integer is positive (> 0).

int.is_positive(4)
pub fn is_negative(n: Int) -> Bool

Check if an integer is negative (< 0).

int.is_negative(-4)
pub fn sign(n: Int) -> Int

Return the sign of an integer: -1, 0, or 1.

int.sign(-10)
pub fn pow(base: Int, exp: Int) -> Int

Compute base raised to the exponent power (non-negative exponent).

int.pow(2, 8)
pub fn gcd(a: Int, b: Int) -> Int

Compute greatest common divisor (Euclidean algorithm).

int.gcd(12, 8)
pub fn lcm(a: Int, b: Int) -> Int

Compute least common multiple.

int.lcm(4, 6)

list

List utilities for Donna.

Functions

pub fn length(xs: List(a)) -> Int

Return the number of elements in a list.

list.length([1, 2, 3])
pub fn tail(xs: List(a)) -> List(a)

Get all elements after the first, or empty list if empty.

list.tail([1, 2, 3])
pub fn is_empty(xs: List(a)) -> Bool

Check if a list is empty.

list.is_empty([])
pub fn append(xs: List(a), ys: List(a)) -> List(a)

Append two lists together.

list.append([1, 2], [3])
pub fn reverse(xs: List(a)) -> List(a)

Reverse a list.

list.reverse([1, 2, 3])
pub fn sum(xs: List(Int)) -> Int

Sum a list of integers.

list.sum([1, 2, 3])
pub fn nth(xs: List(a), n: Int, default: a) -> a

Get the nth element (0-indexed), or default if out of bounds.

list.nth([10, 20], 1, 0)
pub fn flatten(xs: List(List(a))) -> List(a)

Flatten a list of lists.

list.flatten([[1, 2], [3]])
pub fn take(xs: List(a), n: Int) -> List(a)

Take the first n elements.

list.take([1, 2, 3], 2)
pub fn drop(xs: List(a), n: Int) -> List(a)

Drop the first n elements.

list.drop([1, 2, 3], 1)
pub fn repeat(val: a, n: Int) -> List(a)

Create a list of n copies of a value.

list.repeat("x", 3)
pub fn range(start: Int, end: Int) -> List(Int)

Create a list of integers from start to end (exclusive).

list.range(0, 3)
pub fn contains_int(xs: List(Int), val: Int) -> Bool

Check if a list contains an integer value.

list.contains_int([1, 2, 3], 2)
pub fn contains_str(xs: List(String), val: String) -> Bool

Check if a list contains a string value.

list.contains_str(["a", "b"], "b")
pub fn zip_length(xs: List(a)) -> Int

Zip two lists into a list of pairs (as 2-tuples).

list.zip_length(["a", "b"])
pub fn minimum(xs: List(Int), default: Int) -> Int

Get the minimum of a list of integers (or default if empty).

list.minimum([3, 1, 4], 0)
pub fn maximum(xs: List(Int), default: Int) -> Int

Get the maximum of a list of integers (or default if empty).

list.maximum([3, 1, 4], 0)
pub fn is_sorted(xs: List(Int)) -> Bool

Check if a list of integers is sorted in ascending order.

list.is_sorted([1, 2, 3])
pub fn map(xs: List(a), f: fn(a) -> b) -> List(b)

Apply a function to every element, returning a new list.

list.map([1, 2, 3], fn(n: Int) -> n * 2)
pub fn filter(xs: List(a), f: fn(a) -> Bool) -> List(a)

Keep only elements for which the predicate returns True.

list.filter([1, 2, 3], fn(n: Int) -> n > 1)
pub fn fold(xs: List(a), init: b, f: fn(b, a) -> b) -> b

Fold left: combine elements with an accumulator.

list.fold([1, 2, 3], 0, fn(acc: Int, n: Int) -> acc + n)
pub fn fold_right(xs: List(a), init: b, f: fn(a, b) -> b) -> b

Fold right: combine elements right-to-left.

list.fold_right([1, 2, 3], 0, fn(n: Int, acc: Int) -> n + acc)
pub fn any(xs: List(a), f: fn(a) -> Bool) -> Bool

Check if any element satisfies the predicate.

list.any([1, 2, 3], fn(n: Int) -> n > 2)
pub fn all(xs: List(a), f: fn(a) -> Bool) -> Bool

Check if all elements satisfy the predicate.

list.all([2, 4], fn(n: Int) -> n % 2 == 0)
pub fn find(xs: List(a), f: fn(a) -> Bool, default: a) -> a

Find the first element satisfying the predicate, or default if none.

list.find([1, 2, 3], fn(n: Int) -> n > 1, 0)
pub fn flat_map(xs: List(a), f: fn(a) -> List(b)) -> List(b)

Flat-map: apply f to each element and concatenate the results.

list.flat_map([1, 2], fn(n: Int) -> [n, n])
pub fn count(xs: List(a), f: fn(a) -> Bool) -> Int

Count elements satisfying the predicate.

list.count([1, 2, 3], fn(n: Int) -> n > 1)
pub fn zip_with(xs: List(a), ys: List(b), f: fn(a, b) -> c) -> List(c)

Zip two lists, applying f to corresponding pairs.

list.zip_with([1, 2], [3, 4], fn(a: Int, b: Int) -> a + b)
pub fn each(xs: List(a), f: fn(a) -> Nil) -> Nil

Each: apply a function for its side effects.

list.each(["a", "b"], fn(s: String) -> echo s)

string

String utilities for Donna.

Functions

pub fn length(s: String) -> Int

Return the number of bytes in a string.

string.length("Donna")
pub fn concat(a: String, b: String) -> String

Concatenate two strings.

string.concat("Don", "na")
pub fn equal(a: String, b: String) -> Bool

Check if two strings are equal.

string.equal("a", "a")
pub fn is_empty(s: String) -> Bool

Check if a string is empty.

string.is_empty("")
pub fn char_at(s: String, i: Int) -> Int

Get the byte value of the character at position i.

string.char_at("Donna", 0)
pub fn char_str(s: String, i: Int) -> String

Get the character (as a 1-byte String) at position i.

string.char_str("Donna", 0)
pub fn slice(s: String, pos: Int, len: Int) -> String

Get a substring starting at pos with given length.

string.slice("Donna", 1, 3)
pub fn starts_with(s: String, prefix: String) -> Bool

Check if string starts with a given prefix.

string.starts_with("Donna", "Don")
pub fn ends_with(s: String, suffix: String) -> Bool

Check if string ends with a given suffix.

string.ends_with("Donna", "na")
pub fn from_int(n: Int) -> String

Convert an Int to its string representation.

string.from_int(42)
pub fn repeat(s: String, n: Int) -> String

Repeat a string n times.

string.repeat("ha", 3)
pub fn reverse(s: String) -> String

Reverse a string (byte-by-byte).

string.reverse("abc")
pub fn contains(s: String, sub: String) -> Bool

Return True if s contains sub as a substring.

string.contains("hello Donna", "Donna")
pub fn index_of(s: String, sub: String) -> Int

Return the index of the first occurrence of sub in s, or -1 if not found.

string.index_of("hello Donna", "Donna")
pub fn index_of_from(s: String, sub: String, from: Int) -> Int

Return the index of sub in s at or after from, or -1 if not found.

string.index_of_from("abcabc", "abc", 1)
pub fn split(s: String, sep: String) -> List(String)

Split a string by a separator. Returns list of parts.

string.split("a,b,c", ",")
pub fn trim_start(s: String) -> String

Remove leading whitespace (space, tab, carriage return, newline).

string.trim_start("  Donna")
pub fn trim_end(s: String) -> String

Remove trailing whitespace.

string.trim_end("Donna  ")
pub fn trim(s: String) -> String

Remove leading and trailing whitespace.

string.trim("  Donna  ")
pub fn replace(s: String, from: String, to: String) -> String

Replace all occurrences of from with to in s.

string.replace("hello world", "world", "Donna")
pub fn join(parts: List(String), sep: String) -> String

Join a list of strings with a separator between each element.

string.join(["a", "b"], ",")
pub fn pad_left(s: String, width: Int, ch: String) -> String

Pad a string on the left to at least width characters using ch.

string.pad_left("42", 5, "0")
pub fn is_digits(s: String) -> Bool

Return True if the string contains only digits (ASCII 0-9).

string.is_digits("123")
pub fn to_int(s: String) -> Int

Parse a string as an integer. Returns 0 if the string is not a valid integer.

string.to_int("42")
pub fn lowercase(s: String) -> String

Convert all ASCII uppercase letters in a string to lowercase.

string.lowercase("DONNA")
pub fn to_slug(s: String) -> String

Convert a string to a URL-friendly slug: lowercase, spaces become hyphens, non-alphanumeric characters (except hyphens) are dropped.

string.to_slug("Hello Donna!")

External functions

@external pub fn char_from_code(n: Int) -> String

Create a 1-byte string from a character code (byte value).

string.char_from_code(65)

shell

Shell execution utilities.

Functions

pub fn getenv(name: String) -> String

Get the value of an environment variable. Returns "" if not set.

shell.getenv("HOME")
pub fn flush() -> Int

Flush stdout — ensures all buffered output is written before exec.

shell.flush()
pub fn run(cmd: String) -> Int

Run a raw shell command string. Returns the exit code.

shell.run("true")
pub fn capture(cmd: String) -> String

Capture the stdout of a raw shell command. Returns the output as a string.

shell.capture("printf hello")
pub fn exec(cmd: String, args: List(String)) -> Int

Execute a command with a list of arguments. Returns the exit code.

shell.exec("printf", ["hello"])
pub fn output(cmd: String, args: List(String)) -> String

Capture the stdout of a command with a list of arguments.

shell.output("printf", ["hello"])
pub fn output_with_err(cmd: String, args: List(String)) -> String

Capture the stdout and stderr of a command with a list of arguments.

shell.output_with_err("sh", ["-c", "echo err >&2"])
pub fn exec_in(cmd: String, args: List(String), dir: String) -> Int

Execute a command in a specific working directory. Returns the exit code.

shell.exec_in("pwd", [], "/tmp")