The Fly standard library is organised in namespaces. Import a namespace with import, then call its functions using standard return-type syntax. const parameters are read-only inputs; the return value is assigned directly at the call site.
fly.str
String utilities. Transform functions return a heap-allocated string — the caller is responsible for freeing it.
import fly.str
Conversion
convert
public string convert(const int src)
Returns the decimal string representation of src.
string s = str.convert(42) // s = "42"
Query
len
public int len(const string src)
Returns the number of characters in src.
isEmpty
public bool isEmpty(const string src)
Returns true if src has zero length.
equals
public bool equals(const string a, const string b)
Returns true if a and b are identical.
equalsIgnoreCase
public bool equalsIgnoreCase(const string a, const string b)
Returns true if a and b are equal ignoring case.
contains
public bool contains(const string src, const string sub)
Returns true if sub appears anywhere in src.
startsWith
public bool startsWith(const string src, const string prefix)
Returns true if src begins with prefix.
endsWith
public bool endsWith(const string src, const string suffix)
Returns true if src ends with suffix.
indexOf
public int indexOf(const string src, const string sub)
Returns the index of the first occurrence of sub in src, or -1 if not found.
lastIndexOf
public int lastIndexOf(const string src, const string sub)
Returns the index of the last occurrence of sub in src, or -1 if not found.
count
public int count(const string src, const string sub)
Returns the number of non-overlapping occurrences of sub in src.
Example:
import fly.str
void main() {
string msg = "Hello, Fly!"
int length = str.len(msg) // length = 11
bool empty = str.isEmpty(msg) // empty = false
bool found = str.contains(msg, "Fly") // found = true
}
Transform
toUpper
public string toUpper(const string src)
Returns an upper-case copy of src.
toLower
public string toLower(const string src)
Returns a lower-case copy of src.
trim
public string trim(const string src)
Returns a copy of src with leading and trailing whitespace removed.
trimLeft
public string trimLeft(const string src)
Returns a copy of src with leading whitespace removed.
trimRight
public string trimRight(const string src)
Returns a copy of src with trailing whitespace removed.
substring
public string substring(const string src, const int start, const int end)
Returns the substring of src from index start (inclusive) to end (exclusive).
replace
public string replace(const string src, const string from, const string to)
Returns a copy of src with all occurrences of from replaced by to.
repeat
public string repeat(const string src, const int count)
Returns src repeated count times.
concat
public string concat(const string a, const string b)
Returns the concatenation of a and b.
Example:
import fly.str
void main() {
string result = str.concat("Hello, ", "Fly!") // result = "Hello, Fly!"
result = str.toUpper(result) // result = "HELLO, FLY!"
}
fly.math
Mathematical functions and a random-number generator (xoshiro256**).
import fly.math
Types
public struct fly_rng {
ulong s0
ulong s1
ulong s2
ulong s3
}
State for the xoshiro256** PRNG. Initialise with randSeed before use.
Base
absI / absF
public long absI(const long x)
public double absF(const double x)
Absolute value for integers and floats.
sign
public int sign(const double x)
Returns 1 if x > 0, -1 if x < 0, 0 if x == 0.
minI / minF
public long minI(const long a, const long b)
public double minF(const double a, const double b)
Returns the smaller of a and b.
maxI / maxF
public long maxI(const long a, const long b)
public double maxF(const double a, const double b)
Returns the larger of a and b.
clampI / clampF
public long clampI(const long x, const long lo, const long hi)
public double clampF(const double x, const double lo, const double hi)
Clamps x to the range [lo, hi].
gcd
public long gcd(const long a, const long b)
Greatest common divisor of a and b.
lcm
public long lcm(const long a, const long b)
Least common multiple of a and b.
divmod
public void divmod(const long a, const long b, long out_q, long out_r)
Writes quotient into out_q and remainder into out_r.
Trigonometry
public double sin(const double x)
public double cos(const double x)
public double tan(const double x)
public double asin(const double x)
public double acos(const double x)
public double atan(const double x)
public double atan2(const double y, const double x)
public double sinh(const double x)
public double cosh(const double x)
public double tanh(const double x)
public double hypot(const double a, const double b)
toRadians / toDegrees
public double toRadians(const double x)
public double toDegrees(const double x)
Convert between degrees and radians.
Exponential & Logarithms
public double sqrt(const double x)
public double cbrt(const double x)
public double pow(const double base, const double exp)
public double exp(const double x)
public double exp2(const double x)
public double log(const double x)
public double log2(const double x)
public double log10(const double x)
public double logN(const double x, const double n)
logN computes log base n of x.
Rounding
public double floor(const double x)
public double ceil(const double x)
public double round(const double x)
public double trunc(const double x)
public double roundTo(const double x, const int n)
roundTo(x, n) rounds x to n decimal places (negative n rounds to tens, hundreds, …).
Classification
isNaN / isInf / isFinite
public bool isNaN(const double x)
public bool isInf(const double x)
public bool isFinite(const double x)
approxEqual
public bool approxEqual(const double a, const double b, const double epsilon)
Returns true if |a − b| ≤ epsilon.
copySign
public double copySign(const double x, const double y)
Returns x with the sign of y.
Bitwise
public bool isPow2(const long n)
public long nextPow2(const long n)
public int popcount(const long n)
public int leadingZeros(const long n)
public int trailingZeros(const long n)
Random (xoshiro256**)
randSeed
public void randSeed(fly_rng rng, const ulong seed)
Seeds the RNG state from seed using SplitMix64.
rngNext
public ulong rngNext(fly_rng rng)
Advances the RNG and returns the next raw 64-bit value (also updates rng).
randFloat
public double randFloat(fly_rng rng)
Returns a uniformly distributed double in [0, 1).
randInt
public long randInt(fly_rng rng, const long a, const long b)
Returns a uniformly distributed integer in [a, b].
randNormal
public double randNormal(fly_rng rng, const double mu, const double sigma)
Returns a sample from the normal distribution N(μ, σ) using Box-Muller.
Special functions
public double fma(const double a, const double b, const double c)
public double lerp(const double a, const double b, const double t)
public double saturate(const double x)
public long factorialI(const int n)
public double factorialF(const int n)
public long comb(const long n, const long k)
public long perm(const long n, const long k)
public double erf(const double x)
public double erfc(const double x)
public double gamma(const double x)
public double asinh(const double x)
public double acosh(const double x)
public double atanh(const double x)
fma(a, b, c) = a*b + c (fused multiply-add).
lerp(a, b, t) = a*(1−t) + b*t.
saturate(x) clamps x to [0, 1].
Example:
import fly.math
void main() {
fly_rng rng = new fly_rng()
math.randSeed(rng, 42)
double v = math.randFloat(rng) // v in [0, 1)
long n = math.randInt(rng, 1, 10) // n in [1, 10]
double s = math.sqrt(2.0) // s ≈ 1.4142
}
fly.mem
Raw memory operations and typed read/write primitives.
import fly.mem
Types
public struct Ptr {
ulong addr
}
A raw memory address wrapper (void* equivalent).
Allocation
alloc
public long alloc(const ulong size)
Allocates size bytes and returns the raw address.
realloc
public long realloc(const long ptr, const ulong newSize)
Resizes a previous allocation; returns the new address (may differ from ptr).
free
public void free(const long ptr, const ulong size)
Frees a previously allocated block.
isNull
public bool isNull(const long ptr)
Returns true if ptr is 0 (unset).
toPtr
public Ptr toPtr(const long addr)
Wraps a raw address as a Ptr.
Bulk operations
copy
public void copy(const long dst, const long src, const ulong size)
Copies size bytes from src to dst (non-overlapping regions).
move
public void move(const long dst, const long src, const ulong size)
Copies size bytes, handling overlapping regions correctly.
zero
public void zero(const long dst, const ulong size)
Fills size bytes at dst with zeroes.
compare
public int compare(const long a, const long b, const ulong size)
Returns 0 if equal, < 0 if a < b, > 0 if a > b (C memcmp semantics).
Typed reads
public byte readByte(const long ptr, const int offset)
public short readShort(const long ptr, const int offset)
public int readInt(const long ptr, const int offset)
public long readLong(const long ptr, const int offset)
All offsets are in bytes.
Typed writes
public void writeByte(const long ptr, const int offset, const byte val)
public void writeShort(const long ptr, const int offset, const short val)
public void writeInt(const long ptr, const int offset, const int val)
public void writeLong(const long ptr, const int offset, const long val)
fly.os.env
Process environment, command-line arguments, working directory, and process control.
import fly.os.env
Types
public struct StringArray {
long items
int count
}
A heap-allocated array of Fly strings returned by functions that produce variable-length string lists.
Environment variables
get
public string get(const string key)
Returns the value of environment variable key, or an empty string if not set.
set
public void set(const string key, const string value)
Sets key to value, overwriting any existing value.
delete
public void delete(const string key)
Removes key from the environment. No-op if not present.
all
public StringArray all()
Returns all environment variables as "KEY=VALUE" strings.
allCount
public int allCount()
Returns the number of environment variables currently set.
expand
public string expand(const string s)
Replaces $VAR and ${VAR} references in s with their values. Unknown variables expand to an empty string.
Working directory
cwdGet
public string cwdGet()
Returns the current working directory path.
cwdSet
public void cwdSet(const string path)
Changes the current working directory to path.
Arguments & system info
argsGet
public StringArray argsGet()
Returns all command-line arguments (args[0] is the executable path).
argsCount
public int argsCount()
Returns the number of command-line arguments (including argv[0]).
hostname
public string hostname()
Returns the system hostname, or an empty string on failure.
osname
public string osname()
Returns the OS name, e.g. "linux" or "darwin".
exit
public void exit(const int code)
Terminates the process with the given exit code. Never returns.
fly.os.fs
File system operations.
import fly.os.fs
Types
public struct File {
int fd
byte flags
}
An open OS file descriptor. Obtain via open(), create(), or openOpts(); release via close().
public struct Stat {
ulong size
ulong mtime_sec
ulong mtime_nsec
uint mode
int is_file
int is_dir
int is_symlink
}
File metadata. Times are Unix epoch seconds/nanoseconds.
public struct DirEntry {
string name
Stat stat
}
A single directory entry with its basename and metadata.
public struct DirEntries {
long items
ulong len
ulong cap
}
A heap-allocated array of DirEntry values.
Open / close
open
public File open(const string path)
Opens path for reading (O_RDONLY). Check out.fd >= 0 for success.
create
public File create(const string path)
Creates or truncates path for writing (O_WRONLY|O_CREAT|O_TRUNC, mode 0644).
openOpts
public File openOpts(const string path, const int flags, const int perm)
Opens path with explicit flags and permission bits (follow open(2) conventions).
close
public void close(File f)
Closes the file descriptor of f.
sync
public void sync(File f)
Calls fsync on f, flushing OS buffers to persistent storage.
Read / write (path-based)
read
public fly.os.io.Buf read(const string path)
Reads the entire file at path into a heap-allocated Buf. out.size == 0 if the file is empty or missing.
readStr
public string readStr(const string path)
Reads the entire file at path and returns its contents as a string.
write
public void write(const string path, fly.os.io.Buf data, const int perm)
Writes data to path, creating or truncating the file.
writeStr
public void writeStr(const string path, const string content, const int perm)
Writes string content to path, creating or truncating the file.
append
public void append(const string path, fly.os.io.Buf data, const int perm)
Appends data to path, creating the file if needed.
appendStr
public void appendStr(const string path, const string content, const int perm)
Appends string content to path, creating the file if needed.
Binary read / write
readStr and writeStr go through the platform CRT in text mode. On
Windows that means a read collapses \r\n into \n and stops at a 0x1A
byte, and a write expands every \n into \r\n. For source text that is
harmless; for a tarball, an image or any other byte-exact payload it is silent
corruption. These two switch the descriptor to binary mode before a single byte
moves, and are ordinary text I/O on POSIX, where nothing is translated.
readBytes
public string readBytes(const string path)
Reads the whole file verbatim — no newline translation, no early stop at
0x1A. Empty when the file is empty or missing.
writeBytes
public void writeBytes(const string path, const string content, const int perm)
Writes content verbatim, with no newline translation. Use this for any
payload that is not source text.
Seek
seekTo
public long seekTo(File f, const long offset, const int whence)
Moves the file offset. whence: 0=SEEK_SET, 1=SEEK_CUR, 2=SEEK_END. Returns the new offset.
seekPos
public long seekPos(File f)
Returns the current file offset (SEEK_CUR with offset 0).
Metadata
stat / lstat
public Stat stat(const string path)
public Stat lstat(const string path)
stat follows symlinks; lstat reports the symlink itself.
size
public ulong size(const string path)
Returns the byte size of the file. Returns 0 if the file does not exist.
exists
public bool exists(const string path)
Returns true if path exists (any file type).
isFile / isDir
public bool isFile(const string path)
public bool isDir(const string path)
File operations
truncate
public void truncate(const string path, const long size)
Truncates the file to exactly size bytes (extends with null bytes if shorter).
chmod
public void chmod(const string path, const int mode)
Changes the permission bits of path (e.g. 0644 = 420).
delete
public void delete(const string path)
Removes the file or empty directory at path.
copy
public void copy(const string src, const string dst)
Copies the file at src to dst (creates or truncates dst, mode 0644).
move / rename
public void move(const string src, const string dst)
public void rename(const string src, const string dst)
Renames src to dst (aliases for rename(2)).
Directory operations
dirCreate
public void dirCreate(const string path, const int perm)
Creates a single directory. Fails if any parent is missing.
dirCreateAll
public void dirCreateAll(const string path, const int perm)
Creates path and all missing parent directories (mkdir -p).
dirDelete
public void dirDelete(const string path)
Removes an empty directory.
dirDeleteAll
public void dirDeleteAll(const string path)
Removes path and all its contents recursively (rm -rf).
dirRead
public DirEntries dirRead(const string path)
Returns all entries in the directory at path.
Symlinks & temporary files
symlinkCreate
public void symlinkCreate(const string target, const string link)
Creates a symbolic link link pointing to target.
symlinkRead
public string symlinkRead(const string path)
Returns the target of the symbolic link at path.
tempFile
public string, File tempFile(const string dir, const string pattern)
Creates a temporary file in dir using pattern as a name template. Returns the path and an open File.
tempDir
public string tempDir(const string dir, const string pattern)
Creates a temporary directory. Returns its path.
fly.os.io
Byte-stream I/O interfaces and utilities.
import fly.os.io
Types
public struct Buf {
long ptr
ulong size
ulong cap
}
A heap-allocated byte buffer. ptr points to the first byte; size is the number of valid bytes; cap is the total allocated capacity.
public interface Reader {
long read(Buf buf, const ulong n)
void close()
}
Sequential byte-stream source. read fills buf with up to n bytes and returns the count read; returns 0 at EOF.
public interface Writer {
long write(Buf buf, const ulong n)
void flush()
void close()
}
Sequential byte-stream sink. write sends up to n bytes from buf and returns the count written.
public class FileReader : Reader { int fd }
public class FileWriter : Writer { int fd }
public class BufReader : Reader { ... }
public class BufWriter : Writer { ... }
Constructor helpers
fileReader
public Reader fileReader(const int fd)
Wraps a raw OS file descriptor as a Reader.
fileWriter
public Writer fileWriter(const int fd)
Wraps a raw OS file descriptor as a Writer.
readerNew
public BufReader readerNew(Reader inner, const ulong cap)
Wraps inner in a BufReader with a cap-byte internal buffer.
writerNew
public BufWriter writerNew(Writer inner, const ulong cap)
Wraps inner in a BufWriter with a cap-byte internal buffer.
Read utilities
readAll
public Buf readAll(Reader r)
Reads from r until EOF and returns all data in a freshly allocated Buf.
readLine
public string readLine(Reader r)
Reads bytes until '\n' or EOF and returns the line content (without the trailing newline).
readExact
public Buf readExact(Reader r, const ulong n)
Reads exactly n bytes, looping over short reads.
Neither readAll nor a bare read can frame a length-delimited message on a
stream that never ends: readAll waits for EOF, and a read is allowed to return
fewer bytes than asked for. The returned Buf's size is the only sentinel — a
size below n means EOF (or an error) arrived first.
readLines
public fly.os.env.StringArray readLines(Reader r)
Reads all lines from r until EOF and returns them as a StringArray.
Binary mode
setBinaryMode
public bool setBinaryMode(const int fd)
Stops the platform CRT from translating this descriptor's bytes; a no-op on
POSIX, where nothing is translated. Returns false on error.
On Windows the UCRT opens descriptors in text mode: reads collapse \r\n into
\n and stop at a 0x1A byte, writes expand every \n into \r\n. Any
byte-exact protocol must call this on its descriptors first — a
Content-Length: framed stream over stdio is destroyed without it. For files,
use fs.readBytes / fs.writeBytes, which do this themselves.
Write utilities
writeAll
public bool writeAll(Writer w, Buf buf)
Writes all bytes of buf to w. Returns true on success.
writeString
public bool writeString(Writer w, const string s)
Writes the bytes of string s to w. Returns true on success.
Copy utilities
copy
public long copy(Reader src, Writer dst)
Copies all bytes from src to dst until EOF. Returns the total byte count.
copyN
public long copyN(Reader src, Writer dst, const ulong n)
Copies at most n bytes from src to dst. Returns the actual count.
pipe
public long pipe(Reader pipe_r, Writer pipe_w)
Alias for copy.
Console output
print / printLn
public void print(const string s)
public void printLn(const string s)
Write s to stdout. printLn appends a newline.
printErr / printErrLn
public void printErr(const string s)
public void printErrLn(const string s)
Write s to stderr. printErrLn appends a newline.
Example:
import fly.os.fs
import fly.os.io
void main() {
fly.os.fs.File f = fs.open("notes.txt")
Reader r = io.fileReader(f.fd)
string line = io.readLine(r)
io.printLn(line)
r.close()
}
fly.os.path
Path manipulation utilities.
import fly.os.path
Composition
join
public string join(const string base, const string comp)
Joins base and comp with exactly one / separator.
joinN
public string joinN(const string parts, const int n)
Joins n path segments from the array parts.
absolute
public string absolute(const string path)
Returns the absolute form of path (resolves relative to the current working directory).
normalize
public string normalize(const string path)
Resolves . and .. components and removes duplicate separators.
normalizeInPlace
public void normalizeInPlace(string path)
Normalizes path in place (modifies the string directly).
rel
public string rel(const string base, const string target)
Returns the relative path from base to target.
Decomposition
basename
public string basename(const string path)
Returns the last path component (filename with extension).
dirname
public string dirname(const string path)
Returns all but the last path component.
ext
public string ext(const string path)
Returns the file extension including the leading dot, or an empty string.
stem
public string stem(const string path)
Returns the filename without extension.
split
public string, string split(const string path)
Returns (dirname, basename) as two values.
splitExt
public string, string splitExt(const string path)
Returns (stem, ext) as two values.
comp
public fly.os.env.StringArray comp(const string path)
Returns all path components as a StringArray.
compCount
public int compCount(const string path)
Returns the number of path components.
sep
public byte sep()
Returns the platform path separator byte (/ on Unix).
Predicates
isAbsolute / isRelative
public bool isAbsolute(const string path)
public bool isRelative(const string path)
isFile / isDir / isSym
public bool isFile(const string path)
public bool isDir(const string path)
public bool isSym(const string path)
Glob & pattern matching
glob
public fly.os.env.StringArray glob(const string pattern)
Returns all paths matching the glob pattern.
globCount
public int globCount(const string pattern)
Returns the count of paths matching pattern.
match
public bool match(const string pattern, const string name)
Returns true if name matches the glob pattern.
fly.os.proc
Spawning child processes. No shell is involved: the program is executed
directly with an argument vector, so nothing here depends on /bin/sh — which
does not exist on Windows — and no argument needs quoting.
import fly.os.proc
Types
An ArgList is an opaque pointer handle, not a class: a header-declared
class carrying a generic does not survive the archive boundary intact. Build it
with argsNew, fill it with argsAdd, release it with argsFree. Pass 0 for
a command that takes no arguments.
Argument lists
argsNew
public pointer argsNew()
Allocates an empty ArgList and returns its handle.
argsAdd
public void argsAdd(const pointer h, const string a)
Appends a copy of a to the list, growing it if needed.
argsFree
public void argsFree(const pointer h)
Releases the list and every string it owns.
Execution
exec
public int exec(const string path, const pointer h)
Spawns path with argv[0] = path followed by the ArgList arguments (h may
be 0), inherits the environment and waits. Returns the child's exit code
(0–255), 128 + signo if it was killed by a signal, or -1 if the spawn
failed.
run
public int run(const string path)
Convenience: exec with no extra arguments.
execCapture
public int execCapture(const string path, const pointer h, const string outPath)
Like exec, but the child's stdout is redirected to outPath (created and
truncated); the caller reads the file afterwards. Same return contract as
exec.
stderr is inherited, not discarded — a failing command's diagnostics reach the user instead of vanishing.
import fly.os.proc
import fly.os.fs
void main() {
pointer args = proc.argsNew()
proc.argsAdd(args, "rev-parse")
proc.argsAdd(args, "HEAD")
int rc = proc.execCapture("git", args, "head.txt")
proc.argsFree(args)
if rc == 0 {
string sha = fs.readStr("head.txt")
}
}
fly.os.time
Wall clock, monotonic clock, durations, and date formatting.
import fly.os.time
Types
public struct Time {
long sec
long nsec
}
An absolute point in time (seconds + nanoseconds since the Unix epoch). Negative values represent times before 1970.
public struct Duration {
long nsec
}
An elapsed time interval stored as a nanosecond count.
Current time
now
public Time now()
Returns the current wall-clock time (UTC, Unix epoch).
monotonic
public Time monotonic()
Returns the current monotonic clock value. Use for measuring elapsed time.
nowSec
public long nowSec()
Returns the current Unix timestamp in seconds.
Arithmetic
since
public Duration since(Time t)
Returns the Duration elapsed since t (i.e., now − t).
diff
public Duration diff(Time a, Time b)
Returns b − a. Negative if b is before a.
add
public Time add(Time t, Duration d)
Returns t advanced by duration d.
compare
public int compare(Time a, Time b)
Returns -1 if a < b, 0 if equal, 1 if a > b.
Conversions
unix / unixNano
public long unix(Time t)
public long unixNano(Time t)
Returns the Unix timestamp in seconds or nanoseconds.
fromUnix / fromUnixNano
public Time fromUnix(const long sec)
public Time fromUnixNano(const long nsec)
Constructs a Time from a Unix timestamp.
Duration helpers
durationSecs / durationMillis / durationMicros
public long durationSecs(Duration d)
public long durationMillis(Duration d)
public long durationMicros(Duration d)
Returns the duration as seconds, milliseconds, or microseconds.
durationFormat
public string durationFormat(Duration d)
Returns a human-readable string such as "1h2m3s".
durationFormatNsec
public string durationFormatNsec(const long nsec)
Same as durationFormat but takes a raw nanosecond count.
Formatting & parsing
format
public string format(Time t, const string pattern)
Formats t using a Go-style reference-time pattern. Recognised tokens:
| Token | Meaning |
|---|---|
2006 | 4-digit year |
01 | month (zero-padded) |
02 | day (zero-padded) |
15 | hour (24 h) |
04 | minute |
05 | second |
All other bytes are emitted verbatim.
formatSec
public string formatSec(const long sec, const string pattern)
Formats a raw Unix timestamp (seconds) using the same pattern tokens.
parse
public Time parse(const string s, const string pattern)
Parses a date/time string s according to pattern. Unrecognised bytes are skipped.
parseToSec
public long parseToSec(const string s, const string pattern)
Same as parse, but returns the result as a Unix timestamp in seconds.
Sleep
sleep
public void sleep(Duration d)
Suspends execution for at least the duration d. Returns immediately if d ≤ 0.
Example:
import fly.os.time
void main() {
Time t0 = time.now()
Duration ms100 = new Duration()
ms100.nsec = 100000000
time.sleep(ms100)
Duration elapsed = time.since(t0)
string s = time.durationFormat(elapsed) // e.g. "100ms"
}
fly.sync
Thread primitives: threads, mutexes, read-write mutexes, wait groups, once guards, and semaphores.
import fly.sync
Thread
public struct Thread { long handle }
spawnThread
public Thread spawnThread(const long fn, const long arg, const ulong stack)
Starts fn(arg) in a new OS thread. stack = 0 uses the default stack size (1 MiB).
Mutex
public struct Mutex { long state }
A simple spin/sleep mutual-exclusion lock.
public Mutex newMutex()
public void mutexLock(Mutex m)
public void mutexUnlock(Mutex m)
public bool mutexTryLock(Mutex m)
RWMutex
public struct RWMutex { long state; long waiters }
A read-write lock: multiple concurrent readers or one exclusive writer.
public RWMutex newRWMutex()
public void rwmutexRlock(RWMutex rw)
public void rwmutexRunlock(RWMutex rw)
public void rwmutexWlock(RWMutex rw)
public void rwmutexWunlock(RWMutex rw)
WaitGroup
public struct WaitGroup { long state }
Waits for a collection of goroutine-like tasks to finish.
public WaitGroup newWaitGroup()
public void wgAdd(WaitGroup wg, const int n)
public void wgDone(WaitGroup wg)
public void wgWait(WaitGroup wg)
wgAdd(wg, n) increments the counter by n. wgDone decrements by 1. wgWait blocks until the counter reaches 0.
Once
public struct Once { long state }
Runs an initialisation block exactly once, regardless of concurrent calls.
public Once newOnce()
public bool onceAcquire(Once o)
public void onceRelease(Once o)
Usage pattern:
if sync.onceAcquire(o) {
// initialisation
sync.onceRelease(o)
}
Semaphore
public struct Semaphore { long state }
A counting semaphore.
public Semaphore newSemaphore(const int initial)
public void semaphoreAcquire(Semaphore s)
public void semaphoreRelease(Semaphore s)
public bool semaphoreTryAcquire(Semaphore s)
fly.data
Generic heap-allocated data structures. All collections store long values (raw addresses or integers). Use fly.mem.toPtr / casting to store typed pointers.
import fly.data.list // fly.data.List
import fly.data.stack // fly.data.Stack
import fly.data.queue // fly.data.Queue
import fly.data.deque // fly.data.Deque
import fly.data.set // fly.data.Set
import fly.data.map // fly.data.Map
import fly.data.tree // fly.data.Tree
import fly.data.wrapper // fly.data.Wrapper<T> (generic)
All untyped collections (List, Stack, Queue, …) store long values. To build a typed collection, wrap values in Wrapper<T> and store the wrapper reference — see Wrapper<T> and the List<string> pattern below.
List
Dynamic array with O(1) amortised append and O(1) indexed access.
public class List {
public List()
public void add(const long val)
public long get(const int idx)
public void set(const int idx, const long val)
public int size()
public void remove(const int idx)
public void clear()
public void free()
}
Stack
LIFO stack backed by a dynamic array.
public class Stack {
public Stack()
public void push(const long val)
public long pop()
public long peek()
public bool isEmpty()
public int size()
public void free()
}
Queue
FIFO queue backed by a linked list.
public class Queue {
public Queue()
public void enqueue(const long val)
public long dequeue()
public long peek()
public bool isEmpty()
public int size()
public void free()
}
Deque
Double-ended queue with O(1) push/pop at both ends.
public class Deque {
public Deque()
public void pushBack(const long val)
public void pushFront(const long val)
public long popFront()
public long popBack()
public long peekFront()
public long peekBack()
public bool isEmpty()
public int size()
public void free()
}
Set
Hash set with O(1) average add/has/remove.
public class Set {
public Set()
public void add(const long key)
public bool has(const long key)
public void remove(const long key)
public int size()
public void free()
}
Map
Hash map with long keys and long values, O(1) average operations.
public class Map {
public Map()
public void put(const long key, const long val)
public long get(const long key)
public bool has(const long key)
public void remove(const long key)
public int size()
public void free()
}
Tree
Ordered map backed by a binary search tree, O(log n) operations.
public class Tree {
public Tree()
public void put(const long key, const long val)
public long get(const long key)
public bool has(const long key)
public void remove(const long key)
public int size()
public void free()
}
Wrapper<T>
Generic single-value holder (requires generics, v0.12+). The type parameter T is resolved at compile time via monomorphization — each instantiation (Wrapper<string>, Wrapper<int>, …) is a distinct, zero-overhead type.
public class Wrapper<T> {
public Wrapper(T v)
public T get()
public void set(T v)
}
Basic example:
import fly.data.wrapper
void main() {
// String wrapper
Wrapper<string> ws = new Wrapper<string>("hello")
string s = ws.get() // s = "hello"
ws.set("world")
s = ws.get() // s = "world"
// Integer wrapper
Wrapper<int> wi = new Wrapper<int>(42)
int n = wi.get() // n = 42
wi.set(n + 1)
n = wi.get() // n = 43
}
List<string> Pattern
fly.data.List stores raw long values (object addresses or integers). To maintain a typed list of strings, combine List with Wrapper<string>: each string is boxed into a Wrapper<string> instance, and the instance reference is added to the list.
import fly.data.list
import fly.data.wrapper
void main() {
List lst = new List()
// Add strings — box each into a Wrapper<string>
lst.add(new Wrapper<string>("apple"))
lst.add(new Wrapper<string>("banana"))
lst.add(new Wrapper<string>("cherry"))
int n = lst.size() // n = 3
// Read strings — retrieve wrapper, then unwrap
for int i = 0; i < n; i++ {
Wrapper<string> item = lst.get(i)
string text = item.get()
// use text …
}
lst.free()
}
The same pattern works for any heap-allocated type — replace Wrapper<string> with Wrapper<int>, Wrapper<MyClass>, etc.
Untyped example (raw long):
import fly.data.list
import fly.data.map
void main() {
List l = new List()
l.add(10)
l.add(20)
int n = l.size() // n = 2
long v = l.get(0) // v = 10
Map m = new Map()
m.put(1, 100)
long val = m.get(1) // val = 100
l.free()
m.free()
}
fly.codec
Text encodings. Pure Fly, no FFI. Every decoder reports failure through an
errOut parameter rather than by returning an empty string — decoding an empty
input legitimately yields "".
import fly.codec
Base64
base64Encode
public string base64Encode(const string s)
RFC 4648 §4: the +/ alphabet, = padded. Returns "" only for empty input.
base64Decode
public string base64Decode(const string s, int errOut)
Accepts either alphabet and optional padding. errOut: 0 ok, 1 bad
character (whitespace included), 2 impossible length, 3 non-zero leftover
bits.
base64UrlEncode
public string base64UrlEncode(const string s)
RFC 4648 §5: the -_ alphabet, no padding — safe in a URL path, a query
value or a JWT segment.
base64UrlDecode
public string base64UrlDecode(const string s, int errOut)
The inverse; identical to base64Decode, which already accepts both alphabets.
Percent-encoding
percentEncode
public string percentEncode(const string s)
Escapes everything outside the RFC 3986 unreserved set except the URL
structure characters (/ : ? # [ ] @ ! $ & ' ( ) * + , ; =), so a whole path or
URL passes through intact. Never fails.
percentEncodeComponent
public string percentEncodeComponent(const string s)
Escapes the reserved characters too, leaving only A-Za-z0-9 and - . _ ~.
This is what a single query value or path segment needs: a / or &
inside one must not be read as structure. Never fails.
percentDecode
public string percentDecode(const string s, int errOut)
The inverse of both encoders, accepting hex escapes in either case. errOut:
0 ok, 2 a truncated escape at the end of the input, 4 a % not followed
by two hex digits.
A + is left alone rather than turned into a space: that substitution
belongs to application/x-www-form-urlencoded, not to percent-encoding, and
applying it here would corrupt any path or JSON body containing a plus.
Hex
hexEncode
public string hexEncode(const string s)
Two lowercase hex characters per byte. Never fails.
hexDecode
public string hexDecode(const string s, int errOut)
The inverse, accepting either case. errOut: 0 ok, 1 a non-hex character,
2 an odd length.
fly.hash
SHA-256 and CRC-32, in pure Fly.
import fly.hash
sha256Hex
public string sha256Hex(const string data)
The bare 64-character lowercase hex digest of a string's bytes.
sha256String
public string sha256String(const string data)
"sha256:<hex>" — the prefixed form the lockfile and the registry protocol use.
sha256File
public string sha256File(const string path)
"sha256:<hex>" of a file's contents; "" when the file is missing. Reads the
file in binary mode, so the digest is the same on every platform.
sha256Verify
public bool sha256Verify(const string path, const string expected)
true when the file hashes to expected ("sha256:<hex>"). A missing file
hashes to "" and therefore never matches.
crc32
public uint crc32(const string data)
The CRC-32 of a string's bytes. Empty input is 0.
crc32Hex
public string crc32Hex(const string data)
The CRC-32 as 8 lowercase hex characters.
fly.json
A JSON reader and writer.
import fly.json
A value is an opaque handle (pointer), not a class. Ownership is a tree:
freeValue releases a value and everything below it, and a value handed to
add/put is adopted by its parent — never free it yourself afterwards.
parse reports failure through errOut, using codes 301–310 (301 bad
literal, 302 unexpected byte, 303 unterminated string, 304 bad escape,
305 bad array element, 306 missing object key, 307 missing :, 308 bad
object member, 309 malformed \u, 310 unpaired surrogate). The returned
handle is never 0: on error it is a partially-built tree the caller must
still free.
Numbers keep their raw source text — std has no string→double conversion yet — so
asNumberalways returns0.0. Read numbers withasInt, orasStringfor the literal.
Reading
parse
public pointer parse(const string src, int errOut)
JSON text → the root value.
kind
public int kind(const pointer v)
0 null, 1 bool, 2 number, 3 string, 4 array, 5 object; -1 for a
null handle.
isNull · isBool · isNumber · isString · isArray · isObject
public bool isNull(const pointer v)
public bool isBool(const pointer v)
public bool isNumber(const pointer v)
public bool isString(const pointer v)
public bool isArray(const pointer v)
public bool isObject(const pointer v)
Kind predicates.
asBool · asString · asInt · asNumber
public bool asBool(const pointer v)
public string asString(const pointer v)
public int asInt(const pointer v)
public double asNumber(const pointer v)
asString also returns a number's raw literal text. asInt takes the
integral part of that literal (a leading - is honoured, a fraction or exponent
ignored). Each returns the zero value for any other kind.
size · at
public int size(const pointer v)
public pointer at(const pointer v, const int i)
Array length, and element i — 0 when v is not an array or i is out of
range.
keyCount · keyAt · has · get
public int keyCount(const pointer v)
public string keyAt(const pointer v, const int i)
public bool has(const pointer v, const string key)
public pointer get(const pointer v, const string key)
Object members, in insertion order. get returns 0 when the key is absent
or v is not an object.
freeValue
public void freeValue(const pointer v)
Releases a value and everything below it. Safe on a null handle.
Building
newNull · newBool · newInt · newNumber · newString · newArray · newObject
public pointer newNull()
public pointer newBool(const bool b)
public pointer newInt(const int n)
public pointer newNumber(const string literal)
public pointer newString(const string s)
public pointer newArray()
public pointer newObject()
newNumber takes the literal text verbatim (std has no double→string
formatter). newString stores the value raw; escaping happens at write
time.
add
public void add(const pointer arr, const pointer child)
Appends child to an array, which adopts it. No-op when arr is not an
array.
put
public void put(const pointer obj, const string key, const pointer child)
Sets key on an object, which adopts the value. Replacing an existing key
keeps its original position and frees the old value.
Writing
write
public string write(const pointer v)
Compact serialization. A null handle writes null.
writePretty
public string writePretty(const pointer v, const int indent)
indent spaces per nesting level, newline-separated. indent <= 0 behaves
exactly like write.
escape · unescape
public string escape(const string s)
public string unescape(const string s, int errOut)
The JSON-escaped body of a string, without the surrounding quotes, and its
inverse. unescape decodes the full escape set including \uXXXX and surrogate
pairs (UTF-8 encoded); errOut is 0, 304, 309 or 310.
import fly.json
import fly.os.io
void main() {
pointer root = json.newObject()
json.put(root, "name", json.newString("fly"))
pointer tags = json.newArray()
json.add(tags, json.newString("lang"))
json.put(root, "tags", tags) // the object ADOPTS tags
string text = json.write(root) // {"name":"fly","tags":["lang"]}
io.printLn(text)
int err = 0
pointer back = json.parse(text, err)
io.printLn(json.asString(json.get(back, "name"))) // fly
json.freeValue(back)
json.freeValue(root) // frees tags too
}
A JSON document cannot be written as a Fly string literal: escapes are kept raw, so
"{\"a\":1}"is the literal characters{\"a\":1}and does not parse. Build documents with the constructors above, or read the text from a file or a socket.
fly.net
Blocking IPv4 sockets — TCP client and server, UDP datagrams, and poll sets.
import fly.net
This module declares no classes and no structs: every parameter and return
is a plain long/int/pointer/string, so the generated header is a flat
list of function signatures.
Errors are sentinels, not fail/handle. A socket is a long and
negative means invalid: every function that yields a socket returns < 0 on
failure, and every function that takes one treats a negative handle as an
immediate failure — an unchecked handle propagates harmlessly instead of
faulting.
Addresses are packed host-order ints: a<<24 | b<<16 | c<<8 | d, so
127.0.0.1 is 2130706433. There is no htons or inet_addr anywhere; the
network-order conversion happens inside the runtime.
IPv6 is not supported. Do not call the
fly.runtimesocket externs directly even though the header exports them — their signatures are platform-specific (a socket is anintfd on POSIX and a 64-bitSOCKETon Windows).
Addressing
ipv4
public int ipv4(const int a, const int b, const int c, const int d)
Packs four octets into an address; octets are masked to 0–255.
loopback · anyAddr
public int loopback()
public int anyAddr()
127.0.0.1 and 0.0.0.0 (the wildcard bind address).
ipToStr
public string ipToStr(const int addr)
"a.b.c.d" for a packed address. Never empty.
parseIp
public int parseIp(const string s)
Dotted-quad text → packed address; 0 when s is not one.
DNS and peers
resolve
public int resolve(const string host)
Host name or dotted-quad → packed IPv4; a literal address is parsed without a lookup.
resolveAll · addrCount · addrAt · addrFree
public pointer resolveAll(const string host)
public int addrCount(const pointer h)
public int addrAt(const pointer h, const int i)
public void addrFree(const pointer h)
Every IPv4 address for host as an opaque list; resolveAll returns 0 when
the name does not resolve. addrFree is safe on a null handle.
reverseDns
public string reverseDns(const int addr)
The host name registered for a packed address, or "".
peerAddr · peerPort
public int peerAddr(const long s)
public int peerPort(const long s)
The other end of a connected socket; 0 / -1 when not connected.
Socket lifecycle
socket
public long socket()
A blocking IPv4 TCP socket; < 0 on failure.
close
public void close(const long s)
Releases a socket. A negative handle is ignored.
shutdownWrite · shutdownBoth
public bool shutdownWrite(const long s)
public bool shutdownBoth(const long s)
Half-close the sending side so the peer sees EOF while this side can still read, or stop both directions.
Socket options
reuseAddr
public bool reuseAddr(const long s)
Allows rebinding a port still in TIME_WAIT. POSIX only.
setRecvTimeout · setSendTimeout
public bool setRecvTimeout(const long s, const int ms)
public bool setSendTimeout(const long s, const int ms)
Bound how long a blocking receive or send waits.
setNonBlocking
public bool setNonBlocking(const long s, const bool on)
When on, an operation that would block fails instead.
setNoDelay · setKeepAlive · setBroadcast
public bool setNoDelay(const long s, const bool on)
public bool setKeepAlive(const long s, const bool on)
public bool setBroadcast(const long s, const bool on)
TCP_NODELAY, SO_KEEPALIVE, and SO_BROADCAST (required before a datagram
socket may send to a broadcast address).
setLinger
public bool setLinger(const long s, const bool on, const int sec)
SO_LINGER: with on, close blocks for up to sec seconds while unsent data
drains.
setRecvBuf · setSendBuf
public bool setRecvBuf(const long s, const int bytes)
public bool setSendBuf(const long s, const int bytes)
Kernel buffer sizes; the OS may round the value.
sockError
public int sockError(const long s)
The socket's pending error code, cleared by reading it. 0 means none.
Server
bind · listen · accept
public bool bind(const long s, const int addr, const int port)
public bool listen(const long s, const int backlog)
public long accept(const long s)
port 0 requests an ephemeral port — read it back with localPort. accept
blocks and returns the new socket, < 0 on error.
localPort
public int localPort(const long s)
The port the socket is actually bound to, in host order; -1 on error.
listenOn
public long listenOn(const int addr, const int port, const int backlog)
socket + reuseAddr + bind + listen in one call.
Client
connect · connectTo
public bool connect(const long s, const int addr, const int port)
public long connectTo(const string host, const int port)
connectTo resolves, creates the socket and connects; < 0 on any failure.
Transfer
send · sendAll · sendStr
public long send(const long s, const pointer buf, const int n)
public bool sendAll(const long s, const pointer buf, const int n)
public bool sendStr(const long s, const string data)
send is one attempt and may write fewer bytes than asked; sendAll loops
until everything is out. Sending an empty string succeeds without touching the
socket.
recv · recvExact
public long recv(const long s, const pointer buf, const int n)
public long recvExact(const long s, const pointer buf, const int n)
recv is one blocking receive — 0 at EOF, < 0 on error. recvExact loops
over short reads; a result below n means EOF or an error arrived first.
recvStr · recvUpTo · recvAll
public string recvStr(const long s, const int max)
public string recvUpTo(const long s, const int limit)
public string recvAll(const long s)
One receive into a fresh string; read until EOF or limit bytes; read until EOF.
UDP
socketUdp
public long socketUdp()
A blocking IPv4 UDP socket; bind it with bind.
fromNew · fromAddr · fromPort · fromFree
public pointer fromNew()
public int fromAddr(const pointer from)
public int fromPort(const pointer from)
public void fromFree(const pointer from)
The 8-byte scratch that recvFrom fills with the sender's address and port.
sendTo · sendStrTo
public long sendTo(const long s, const pointer buf, const int n, const int addr, const int port)
public bool sendStrTo(const long s, const string data, const int addr, const int port)
One datagram to addr:port.
recvFrom · recvStrFrom
public long recvFrom(const long s, const pointer buf, const int n, const pointer from)
public string recvStrFrom(const long s, const int max, const pointer from)
One datagram, with the sender written into from.
Poll sets
Watch several sockets at once. A poll set is an opaque handle holding entries; each entry has an index that stays valid until a removal.
pollRead · pollWrite · pollErr · pollHup
public int pollRead() // 1
public int pollWrite() // 2
public int pollErr() // 4
public int pollHup() // 8
The event bits. pollErr and pollHup are always reported whether or not
they were requested.
pollNew · pollFree · pollCount
public pointer pollNew()
public void pollFree(const pointer ps)
public int pollCount(const pointer ps)
pollFree does not close the watched sockets — they belong to the caller.
pollAdd · pollSet · pollRemove
public int pollAdd(const pointer ps, const long s, const int events)
public bool pollSet(const pointer ps, const int i, const int events)
public bool pollRemove(const pointer ps, const int i)
pollAdd returns the new entry's index. pollRemove moves the last entry
into the hole, so indices after a removal are not stable.
pollSocketAt · pollEventsAt
public long pollSocketAt(const pointer ps, const int i)
public int pollEventsAt(const pointer ps, const int i)
What is registered at entry i.
pollWait · pollRevents · pollIsReady
public int pollWait(const pointer ps, const int timeoutMs)
public int pollRevents(const pointer ps, const int i)
public bool pollIsReady(const pointer ps, const int i, const int mask)
pollWait blocks until at least one socket is ready and returns how many are,
0 on timeout, -1 on error; then read each entry's pollRevents.
import fly.net
void main() {
long srv = net.listenOn(net.loopback(), 0, 8)
int port = net.localPort(srv)
long c = net.connectTo("127.0.0.1", port)
net.sendStr(c, "ping")
long conn = net.accept(srv)
string msg = net.recvStr(conn, 64) // "ping"
net.close(conn)
net.close(c)
net.close(srv)
}
fly.net.tls
TLS over a fly.net socket.
import fly.net.tls
Availability is a runtime fact, not a compile-time one — ask
tlsAvailable() before relying on any of this. A real backend is linked only
when the program was built with --tls; without it the
link picks up a no-op stub, so a program that never asked for TLS still links on
a machine with no libssl, and tlsAvailable() tells the truth instead of
failing mysteriously at handshake time.
| Platform | Backend with --tls |
|---|---|
| Linux | OpenSSL (1.1.0 or later) |
| Windows | Schannel |
| macOS | none — tlsAvailable() is false |
A connection is an opaque pointer, 0 = invalid.
Verification is on by default and is a per-connection parameter — there is no global switch. Turning it off accepts any certificate and defeats the point of TLS; it exists only for a host with a self-signed certificate you already trust by other means.
tlsAvailable
public bool tlsAvailable()
true when a real backend is linked into this program.
tlsConnect · tlsConnectOpts
public pointer tlsConnect(const string host, const int port)
public pointer tlsConnectOpts(const string host, const int port, const bool verify, const int timeoutMs)
Resolve, connect and handshake in one call. tlsConnect is tlsConnectOpts
with verification on and no timeout. Both return 0 on any failure, having
closed the socket they opened.
tlsWrap
public pointer tlsWrap(const long sock, const string sniHost, const bool verify)
Puts an already-connected socket into a TLS session. sniHost is sent as the
SNI server name and, when verify, checked against the certificate. The socket
becomes owned by the connection.
tlsSocket
public long tlsSocket(const pointer c)
The underlying socket, for use in a poll set; -1 for a null handle. Reading or
writing it directly would bypass the encryption.
tlsSend · tlsSendStr
public long tlsSend(const pointer c, const pointer buf, const int n)
public bool tlsSendStr(const pointer c, const string data)
One write. Unlike a raw socket this is either all of n or an error — the
record layer does not do short writes.
tlsRecv · tlsRecvStr · tlsRecvAll
public long tlsRecv(const pointer c, const pointer buf, const int n)
public string tlsRecvStr(const pointer c, const int max)
public string tlsRecvAll(const pointer c)
One blocking read (0 at a clean end of session, < 0 on error or timeout),
one read into a fresh string, or everything until the session ends.
tlsLastError
public int tlsLastError(const pointer c)
The backend's raw error code for the last failed operation, 0 when none. Not
translated.
tlsClose · tlsFree
public void tlsClose(const pointer c)
public void tlsFree(const pointer c)
tlsClose sends close_notify, releases the session and closes the socket.
tlsFree releases the session and leaves the socket open. Both are safe on a
null handle — and after either, the handle is dead.
fly.net.http
HTTP/1.1 over fly.net: parse a request, build a response, and a small
blocking client.
import fly.net.http
There are no Request/Response objects: every accessor takes the raw message and re-scans it. That keeps the whole parse/serialize surface pure string-in, string-out — testable without a socket.
CRLF trap: Fly string literals keep escapes raw, so
"\r\n"is four characters, not a line terminator. Build message text with the functions here rather than by hand.
Parsing a request
method · target · version · path · query
public string method(const string raw)
public string target(const string raw)
public string version(const string raw)
public string path(const string raw)
public string query(const string raw)
Request-line fields; "" when it is unparseable. target includes the query,
path is the part before ?.
header · contentLength
public string header(const string raw, const string name)
public int contentLength(const string raw)
Case-insensitive header lookup, value trimmed. contentLength is -1 when the
header is absent or not a number.
headerEnd · body · isComplete
public int headerEnd(const string raw)
public string body(const string raw)
public bool isComplete(const string raw)
Index of the first byte after the CRLFCRLF, the body, and whether the whole
message has arrived — isComplete is the receive loop's stop condition.
isChunked · dechunk · bodyDecoded
public bool isChunked(const string raw)
public string dechunk(const string body)
public string bodyDecoded(const string raw)
Chunked transfer coding. bodyDecoded is the one to reach for: it returns the
body with the transfer coding already removed.
queryParam
public string queryParam(const string raw, const string key)
The value of key in the query string; "" when absent.
Building a response
statusText
public string statusText(const int status)
The reason phrase for a status code; "Unknown" for anything unrecognised.
response · responseWith · responseConn
public string response(const int status, const string contentType, const string bodyStr)
public string responseWith(const int status, const string contentType, const string extraHeaders, const string bodyStr)
public string responseConn(const int status, const string contentType, const string extraHeaders, const bool keepAlive, const string bodyStr)
A complete HTTP/1.1 response. The first two send Connection: close;
responseConn chooses the disposition.
joinHeaders
public string joinHeaders(const string a, const string b)
Combines two header lines into one extraHeaders argument.
Building a request
buildRequest · buildRequestConn
public string buildRequest(const string method, const string targetPath, const string host, const string extraHeaders, const string bodyStr)
public string buildRequestConn(const string method, const string targetPath, const string host, const string extraHeaders, const string bodyStr, const bool keepAlive)
A complete request; buildRequest sends Connection: close, i.e. one exchange
per connection.
basicAuth
public string basicAuth(const string user, const string password)
The value for an Authorization header: "Basic " followed by the base64 of
user:password.
Reading a response
respStatus · respHeader · respBody
public int respStatus(const string raw)
public string respHeader(const string raw, const string name)
public string respBody(const string raw)
Status code (-1 when unparseable), case-insensitive header lookup, and body.
URLs and redirects
urlScheme · urlHost · urlPort · urlPath
public string urlScheme(const string url)
public string urlHost(const string url)
public int urlPort(const string url)
public string urlPath(const string url)
urlPort falls back to 80 for http and 443 for https; urlPath is "/"
when the URL has none.
isRedirect · resolveUrl · redirectTarget
public bool isRedirect(const int status)
public string resolveUrl(const string baseUrl, const string location)
public string redirectTarget(const string resp, const string baseUrl)
isRedirect is a 3xx carrying a Location worth following (304 is not).
resolveUrl makes an absolute URL from a Location value and the URL it came
from.
Multipart bodies
mpNew · mpContentType · mpAddField · mpAddFile · mpFinish · mpFree
public pointer mpNew(const string boundary)
public string mpContentType(const pointer h)
public void mpAddField(const pointer h, const string name, const string value)
public void mpAddFile(const pointer h, const string name, const string filename, const string contentType, const string content)
public string mpFinish(const pointer h)
public void mpFree(const pointer h)
A multipart/form-data builder. boundary must not occur in any part's
content. mpContentType gives the value for the request's Content-Type
header; mpFinish appends the closing delimiter and returns the body.
Client
exchange
public string exchange(const string host, const int port, const string rawRequest)
Connect, send one request, read the whole response, close.
get · getFollow · getStatus
public string get(const string url)
public string getFollow(const string url, const int maxHops)
public int getStatus(const string url)
GET a URL and return the body with the transfer coding removed, optionally
following up to maxHops redirects; or just the status code (-1 on failure).
download · postFile
public bool download(const string url, const string destPath)
public bool postFile(const string url, const string filePath, const string token)
GET a URL into a file (written in binary mode), and POST a file's contents as
application/octet-stream with an optional bearer token.
Keep-alive connections
connOpen · connExchange · connIsClosing · connClose
public long connOpen(const string host, const int port, const int timeoutMs)
public string connExchange(const long s, const string rawRequest)
public bool connIsClosing(const string resp)
public void connClose(const long s)
A connection intended for several exchanges. Check connIsClosing on each
response: it is true when the server will not accept another request.
HTTPS
httpsAvailable · httpsSupported
public bool httpsAvailable()
public bool httpsSupported()
httpsAvailable is the whole-client backend (WinHTTP on Windows);
httpsSupported is true when an https URL can be served at all, by
either that or fly.net.tls.
getSecure · getSecureStatus · downloadSecure · postFileSecure
public string getSecure(const string url)
public int getSecureStatus(const string url)
public bool downloadSecure(const string url, const string destPath)
public bool postFileSecure(const string url, const string filePath, const string token)
The https counterparts. The plain get/download/postFile above dispatch
to these automatically for an https URL.
When no backend is available an https URL fails rather than silently
downgrading to plaintext, and nothing falls back to an external tool.
import fly.net.http
void main() {
string body = http.get("http://example.com/v1/pkg")
int code = http.getStatus("http://example.com/v1/pkg") // 200
}
fly.targz
Gzip decompression (DEFLATE) and the ustar archive format — pure Fly, no FFI, no
platform branches. This is what removes tar from the package-manager path.
import fly.targz
Compression is deliberately not implemented: nothing in the toolchain produces archives, only consumes them.
Every entry point takes an errOut and the caller checks it rather than the
emptiness of the result — inflating an empty stream legitimately yields "".
| Code | Meaning |
|---|---|
| 1 | truncated input — the stream ended mid-symbol |
| 2 | not a gzip stream (bad magic) |
| 3 | unsupported gzip method or reserved flag |
| 4 | invalid DEFLATE block type |
| 5 | invalid Huffman code |
| 6 | a back-reference pointing before the start of the output |
| 7 | CRC-32 mismatch — the payload is corrupt |
| 8 | ISIZE mismatch — the payload is truncated |
| 9 | bad tar header checksum — not an ustar archive, or corrupt |
| 10 | an entry could not be written to disk |
| 11 | an entry whose path escapes the destination directory |
Decompression
isGzip
public bool isGzip(const string data)
true when the data starts with the gzip magic and names DEFLATE as its method.
Cheap enough to use as a dispatch test.
gunzip
public string gunzip(const string data, int errOut)
Decompresses a complete gzip member and verifies it: the CRC-32 catches corruption in transit and the ISIZE catches truncation, which a CRC alone would miss on a stream that happens to end at a block boundary.
inflate
public string inflate(const string data, int errOut)
Decompresses a raw DEFLATE stream, with no gzip or zlib wrapper.
Reading an archive
tarOpen · tarNext · tarFree
public pointer tarOpen(const string data)
public bool tarNext(const pointer h)
public void tarFree(const pointer h)
A reader over the archive bytes, owning its own copy. tarNext advances to the
next real entry — GNU long-name and pax extension records are consumed
rather than reported — and returns false at the end of the archive or on
error.
tarName · tarSize · tarType · tarIsFile · tarIsDir · tarData
public string tarName(const pointer h)
public long tarSize(const pointer h)
public int tarType(const pointer h)
public bool tarIsFile(const pointer h)
public bool tarIsDir(const pointer h)
public string tarData(const pointer h)
The current entry. tarType is the raw typeflag (48/0 regular, 53
directory, 50 symlink); the two predicates spare the caller the ASCII codes.
tarErr
public int tarErr(const pointer h)
0 while the archive reads cleanly, 9 once a header failed its checksum —
tarNext returning false means "end of archive" only when this is 0.
Extracting
safeName
public bool safeName(const string name)
Rejects any entry path that would write outside the destination: an absolute
path, a Windows drive-qualified path, or one containing a .. segment.
Archives arrive off the network from a package registry; without this check a
hostile — or merely careless — tarball can drop a file anywhere the compiler
can write.
extractTar · extractTarGz
public bool extractTar(const string data, const string destDir, int errOut)
public bool extractTarGz(const string archivePath, const string destDir, int errOut)
Unpack an in-memory ustar archive, or read a .tar.gz from disk, verify it and
unpack it — creating parent directories as needed and stopping at the first
problem. extractTarGz is the whole of what tar -xzf was being spawned for.
fly.log
Leveled logging with timestamps, an optional file sink, and the function-trace
hooks behind the compiler's --trace-calls
instrumentation.
import fly.log
import fly.log.LogLevel
Every line goes to stderr as YYYY-MM-DD HH:MM:SS [LEVEL] message;
setFile mirrors it into an append-mode file as well. A message prints when
its level's value is ≤ the configured threshold: ERROR passes every
threshold, TRACE only the most verbose one.
The threshold is lazy: the first emission (or getLevel/isOff) reads the
FLY_LOG_LEVEL environment variable — a level name in any case, or off
to silence everything; unset or unknown falls back to INFO. A program that
calls setLevel/setLevelName/setOff first wins, and the environment is
never consulted. So an instrumented binary is silent by default and turns
into a tracer with nothing but FLY_LOG_LEVEL=trace in the environment.
The call-depth indentation kept by the trace hooks is process-global and not thread-safe; tracing assumes a single-threaded program.
Levels
public enum LogLevel { ERROR, WARN, INFO, DEBUG, TRACE }
The severity ladder. .value runs 1 (ERROR) to 5 (TRACE); .name is
the tag printed between brackets.
setLevel
public void setLevel(const LogLevel level)
Sets the threshold. A message prints when its level's value is ≤ this one.
setLevelName
public void setLevelName(const string name)
setLevel by name, case-insensitive ("error"…"trace"); "off" behaves
like setOff. An unknown name is ignored.
setOff · isOff
public void setOff()
public bool isOff()
setOff silences every level — there is deliberately no OFF enum entry, so
"off" is a state, not a level. isOff reports it.
getLevel
public LogLevel getLevel()
The effective threshold (reading the environment first if nothing was set).
When isOff() it returns ERROR, the least verbose defined entry — check
isOff() to distinguish.
parseLevel · isLevelName
public LogLevel parseLevel(const string name)
public bool isLevelName(const string name)
Name → entry, case-insensitive; an unknown name parses to INFO.
isLevelName tells whether the name is one of the five entries.
setFile
public void setFile(const string path)
Mirrors every printed line into path, appending (the file is created on the
first write). The stderr sink stays active.
reset
public void reset()
Back to the pristine state: threshold unset (the next emission re-reads
FLY_LOG_LEVEL), depth zero, file sink off. Mainly for tests.
Messages
trace · debug · info · warn · err
public void trace(const string msg)
public void debug(const string msg)
public void info(const string msg)
public void warn(const string msg)
public void err(const string msg)
One function per level. The ERROR-level one is err, not error — error is
a reserved type keyword (the io.printErr precedent).
log.setLevel(LogLevel.DEBUG)
log.info("server listening") // 2026-07-31 15:00:27 [INFO] server listening
log.debug("cache warmed") // printed: DEBUG ≤ DEBUG
log.trace("byte-level detail") // filtered: TRACE > DEBUG
Call tracing
The hooks --trace-calls injects at every function entry and exit. They are
ordinary public functions, so hand-written instrumentation can call them too.
All three print at TRACE with two spaces of indentation per call depth.
enter
public void enter(const string name)
Logs > name, then goes one level deeper.
exit · exitFail
public void exit(const string name)
public void exitFail(const string name)
One level back up, then < name — or <! name for a function left through an
unhandled fail.
The mangled symbols of these three functions are part of the compiler's ABI:
--trace-callsemits calls to them by symbol. Renaming them or changing their signatures breaks the instrumentation (the compiler's CodeGenTraceSuite pins the symbols).
fly.assert
Test assertion helpers. All functions call exit(code) on failure.
import fly.assert
errExit
public void errExit(const int code)
Exits the process with code unconditionally.
assertEqI
public void assertEqI(const int got, const int exp, const int code)
Asserts got == exp (integers).
assertEqL
public void assertEqL(const long got, const long exp, const int code)
Asserts got == exp (longs).
assertStr
public void assertStr(const string got, const string exp, const int code)
Asserts got == exp (strings).
assertNotEmpty
public void assertNotEmpty(const string s, const int code)
Asserts that s is not empty.
assertTrue / assertFalse
public void assertTrue(const bool b, const int code)
public void assertFalse(const bool b, const int code)
assertGtI
public void assertGtI(const int got, const int threshold, const int code)
Asserts got > threshold.
assertApprox
public void assertApprox(const double got, const double exp, const int code)
Asserts |got − exp| ≤ 1e-9.
assertApproxEps
public void assertApproxEps(const double got, const double exp, const double eps, const int code)
Asserts |got − exp| ≤ eps.
Example:
import fly.assert
import fly.str
void main() {
int n = str.len("hello")
assert.assertEqI(n, 5, 1) // passes
assert.assertTrue(n > 0, 2) // passes
}